1 #include <iostream> 2 #include <SDL.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 extern "C" 8 { 9 #include <libavcodec/avcodec.h> 10 #include <libavformat/avformat.h> 11 } 12 13 14 using namespace std; 15 #undef main 16 17 const int SCREEN_WIDTH = 640; 18 const int SCREEN_HEIGHT = 480; 19 //We‘ll just be using square tiles for now 20 const int TILE_SIZE = 40; 21 22 void logSDLError(std::ostream &os, const std::string &msg) 23 { 24 os << msg << " error: " << SDL_GetError() << std::endl; 25 } 26 27 28 #define INBUF_SIZE 4096 29 30 int main(int argc, char **argv) 31 { 32 33 /* 34 1.解析文件中流的数量,找出其中的video流id 35 2.找出video流的解码器,yuv格式,高度,宽度,打开解码器 36 3.读取一个包,如果是video对应的流就发到video解码器 37 4.尝试从解码器读取一帧图片 38 //sdl 在开始就初始化 39 5.把一阵图片转为sdl的纹理。 40 6.sdl显示纹理 41 */ 42 char *filepath = "D:\\h264.mkv"; 43 //char *filepath = "d:\image.bmp"; 44 int videoindex; 45 int i,j,k; 46 //AVPacket *pkt; 47 //AVInputFormat* iformat=av_find_input_format("h264"); // 48 int pic_w,pic_h; 49 AVFrame *frame; 50 AVPacket pkt1, *pkt = &pkt1; 51 AVFormatContext *pFormatCtx; 52 53 AVCodec *pCodec; 54 AVCodecContext *c= NULL; 55 int ret = -1; 56 //avcodec_register_all(); 57 av_register_all(); 58 //pkt = av_packet_alloc(); 59 //if (!pkt) 60 // exit(1); 61 pFormatCtx = avformat_alloc_context(); 62 63 if((ret = avformat_open_input(&pFormatCtx,filepath,NULL,NULL))!=0) 64 { 65 char ebuf[1024]; 66 av_strerror(ret, ebuf, 1024); 67 printf("Couldn‘t open input stream ret = %d %s.\n",ret,ebuf); 68 return -1; 69 } 70 if(avformat_find_stream_info(pFormatCtx,NULL)<0) 71 { 72 printf("Couldn‘t find stream information.\n"); 73 return -1; 74 } 75 videoindex = -1; 76 for(i=0; i<pFormatCtx->nb_streams; i++) 77 if(pFormatCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO) 78 { 79 videoindex=i; 80 break; 81 } 82 if(videoindex==-1) 83 { 84 printf("Didn‘t find a video stream.\n"); 85 return -1; 86 } 87 pCodec = avcodec_find_decoder(pFormatCtx->streams[videoindex]->codecpar->codec_id); 88 if (!pCodec) { 89 fprintf(stderr, "Codec not found\n"); 90 exit(-1); 91 } 92 93 c = avcodec_alloc_context3(pCodec); 94 if (!c) { 95 fprintf(stderr, "Could not allocate video codec context\n"); 96 exit(1); 97 } 98 /* 在decode_video.c中有注释 下面这一句很重要,如果没有下面这句话。有height和width 99 设置到解码器,这些参数piexlformat也可以发送到sdl来做显示。 100 否则出现avcodec_send_packet出错"@ 101 [h264 @ 04bd5b00] No start code is found. 102 [h264 @ 04bd5b00] Error splitting the input into NAL units." 103 */ 104 /* For some codecs, such as msmpeg4 and mpeg4, width and height 105 MUST be initialized there because this information is not 106 available in the bitstream. */ 107 108 ret = avcodec_parameters_to_context(c, pFormatCtx->streams[videoindex]->codecpar); 109 if (ret < 0) 110 { 111 fprintf(stderr, "Could not avcodec_parameters_to_context\n"); 112 exit(1); 113 } 114 115 if (avcodec_open2(c, pCodec, NULL) < 0) { 116 fprintf(stderr, "Could not open codec\n"); 117 exit(1); 118 } 119 frame = av_frame_alloc(); 120 if (!frame) { 121 fprintf(stderr, "Could not allocate video frame\n"); 122 exit(1); 123 } 124 125 /* 126 初始化SDL相关的东西 127 */ 128 if (SDL_Init(SDL_INIT_EVERYTHING) != 0){ 129 logSDLError(std::cout, "SDL_Init"); 130 return 1; 131 } 132 133 SDL_Window *window = SDL_CreateWindow("Lesson 2", 100, 100, SCREEN_WIDTH, 134 SCREEN_HEIGHT, SDL_WINDOW_SHOWN); 135 if (window == nullptr){ 136 logSDLError(std::cout, "CreateWindow"); 137 SDL_Quit(); 138 return 1; 139 } 140 SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, 141 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); 142 if (renderer == nullptr){ 143 logSDLError(std::cout, "CreateRenderer"); 144 SDL_DestroyWindow(window); 145 SDL_Quit(); 146 return 1; 147 } 148 149 SDL_RenderClear( renderer ); 150 SDL_RenderPresent( renderer ); 151 152 /* 到时候解码出来的视频帧的格式,width,height 都在pFormatCtx->streams[videoindex]->codecpar里面, 153 ffmpeg 中 sdl_texture_format_map 是一个ffmpeg中pixelformat到sdl中pixelformat的映射表。 154 { AV_PIX_FMT_YUV420P, SDL_PIXELFORMAT_IYUV }, 155 为了简单直接采用了YUV420P的视频来做实验,就直接设置SDL_PIXELFORMAT_IYUV 156 */ 157 158 pic_w = pFormatCtx->streams[videoindex]->codecpar->width; 159 pic_h = pFormatCtx->streams[videoindex]->codecpar->height; 160 cout<<"pic_w="<<pic_w<<" pic_h="<<pic_h<<endl; 161 SDL_Texture* sdlTexture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING,pic_w,pic_h); 162 163 while(av_read_frame(pFormatCtx, pkt)>=0) 164 { 165 if( (pkt->stream_index == videoindex)&&(pkt->size>0)) 166 { puts("@"); 167 ret = avcodec_send_packet(c, pkt); 168 if (ret < 0) 169 { 170 fprintf(stderr, "Error sending a packet for decoding\n"); 171 exit(1); 172 } 173 while (ret >= 0) 174 { 175 ret = avcodec_receive_frame(c, frame); 176 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) 177 break; 178 else if (ret < 0) 179 { 180 fprintf(stderr, "Error during decoding\n"); 181 exit(1); 182 } 183 puts("."); 184 #if 0 185 printf("saving frame %3d\n", dec_ctx->frame_number); 186 fflush(stdout); 187 188 /* the picture is allocated by the decoder. no need to 189 free it */ 190 snprintf(buf, sizeof(buf), "%s-%d", filename, dec_ctx->frame_number); 191 pgm_save(frame->data[0], frame->linesize[0], 192 frame->width, frame->height, buf); 193 #endif 194 /* 195 如何获得像素格式,高度,宽度来进行显示 196 * */ 197 SDL_RenderClear( renderer ); 198 //SDL_UpdateTexture(sdlTexture,NULL,frame->data[0] ,frame->linesize[0]); 199 #if 0 200 // 下面这个函数是不行的? 201 SDL_UpdateTexture(sdlTexture,NULL,frame->data[0] ,frame->linesize[0]); 202 #else 203 // 图像的缩放是在这里完成的,NULL表示窗口对应得缓存全部被填充。后面是图像数据和pitch 204 SDL_UpdateYUVTexture(sdlTexture, NULL, 205 frame->data[0], frame->linesize[0], 206 frame->data[1], frame->linesize[1], 207 frame->data[2], frame->linesize[2]); 208 #endif 209 cout<< "fff"<<endl; 210 SDL_RenderCopy( renderer, sdlTexture, NULL, NULL); 211 SDL_RenderPresent( renderer ); 212 } 213 } 214 215 av_packet_unref(pkt); 216 217 } 218 avcodec_free_context(&c); 219 av_frame_free(&frame); 220 av_packet_free(&pkt); 221 222 SDL_DestroyRenderer(renderer); 223 SDL_DestroyWindow(window); 224 SDL_Quit(); 225 std::cout<<"ok"<<std::endl; 226 227 return 0; 228 }
主要参考ffmpeg 自带的decode_video.c 和 https://blog.csdn.net/leixiaohua1020/article/details/38868499