1. 程式人生 > >ffmpeg +sdl 播放視頻

ffmpeg +sdl 播放視頻

lse troy bit yuv420 clu edi ces 全部 some

  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

ffmpeg +sdl 播放視頻