ffmpeg +sdl 播放视频

  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

 

posted @ 2018-04-07 00:00  mbdkunkka  阅读(793)  评论(0编辑  收藏  举报