【ffmpeg学习】Tutorial 04: Spawning Threads 将解析线程与视频解码线程分开

来源:互联网 发布:新加坡股票行情软件 编辑:程序博客网 时间:2024/04/28 00:00

http://blog.csdn.net/ashqal/article/details/17722935

环境

FFmpeg:2013年9月9日 github master版本

SDL:SDL2

系统:macos 10.8 64位

ffmpeg编译参数:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ./configure --cc=clang --disable-everything  --enable-libfdk_aac --enable-libmp3lame --enable-protocol=file --enable-protocol=file --enable-decoder=aac --enable-decoder=aac --enable-decoder=mp3 --enable-encoder=libmp3lame --enable-encoder=libfdk_aac --enable-demuxer=aac --enable-demuxer=mp3 --enable-muxer=adts --enable-muxer=mp3 --enable-parser=aac --enable-decoder=flv --enable-decoder=h264 --enable-decoder=mpeg4 --enable-demuxer=avi --enable-demuxer=flv --enable-demuxer=h264 --enable-muxer=mp4 --enable-muxer=flv  


代码源自

http://dranger.com/ffmpeg/tutorial04.html



修改后版本

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. // tutorial04.c  
  2. // A pedagogical video player that will stream through every video frame as fast as it can,  
  3. // and play audio (out of sync).  
  4. //  
  5. // This tutorial was written by Stephen Dranger (dranger@gmail.com).  
  6. //  
  7. // Code based on FFplay, Copyright (c) 2003 Fabrice Bellard,  
  8. // and a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)  
  9. // Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1  
  10. //  
  11. // Use the Makefile to build all the samples.  
  12. //  
  13. // Run using  
  14. // tutorial04 myvideofile.mpg  
  15. //  
  16. // to play the video stream on your screen.  
  17.   
  18.   
  19.   
  20. #include <libavcodec/avcodec.h>  
  21. #include <libavformat/avformat.h>  
  22. #include <libavformat/avio.h>  
  23. #include <libswscale/swscale.h>  
  24. #include <libavutil/avstring.h>  
  25.   
  26. #include <SDL2/SDL.h>  
  27. #include <SDL2/SDL_thread.h>  
  28.   
  29. #ifdef __MINGW32__  
  30. #undef main /* Prevents SDL from overriding main() */  
  31. #endif  
  32.   
  33. #include <stdio.h>  
  34. #include <math.h>  
  35.   
  36. #define SDL_AUDIO_BUFFER_SIZE 1024  
  37. #define MAX_AUDIO_FRAME_SIZE 192000  
  38.   
  39. #define MAX_AUDIOQ_SIZE (5 * 16 * 1024)  
  40. #define MAX_VIDEOQ_SIZE (5 * 256 * 1024)  
  41.   
  42. #define FF_ALLOC_EVENT   (SDL_USEREVENT)  
  43. #define FF_REFRESH_EVENT (SDL_USEREVENT + 1)  
  44. #define FF_QUIT_EVENT (SDL_USEREVENT + 2)  
  45.   
  46. #define VIDEO_PICTURE_QUEUE_SIZE 1  
  47.   
  48. typedef struct PacketQueue {  
  49.     AVPacketList *first_pkt, *last_pkt;  
  50.     int nb_packets;  
  51.     int size;  
  52.     SDL_mutex *mutex;  
  53.     SDL_cond *cond;  
  54. } PacketQueue;  
  55.   
  56.   
  57. typedef struct VideoPicture {  
  58.     //SDL_Texture *texture;  
  59.     AVFrame* rawdata;  
  60.     //SDL_Overlay *bmp;  
  61.     int width, height; /* source height & width */  
  62.     int allocated;  
  63. } VideoPicture;  
  64.   
  65. typedef struct VideoState {  
  66.       
  67.     AVFormatContext *pFormatCtx;  
  68.     int             videoStream, audioStream;  
  69.     AVStream        *audio_st;  
  70.     PacketQueue     audioq;  
  71.     uint8_t         audio_buf[(MAX_AUDIO_FRAME_SIZE * 3) / 2];  
  72.     unsigned int    audio_buf_size;  
  73.     unsigned int    audio_buf_index;  
  74.     AVFrame         audio_frame;  
  75.     AVPacket        audio_pkt;  
  76.     uint8_t         *audio_pkt_data;  
  77.     int             audio_pkt_size;  
  78.     AVStream        *video_st;  
  79.     PacketQueue     videoq;  
  80.       
  81.     VideoPicture    pictq[VIDEO_PICTURE_QUEUE_SIZE];  
  82.     int             pictq_size, pictq_rindex, pictq_windex;  
  83.     SDL_mutex       *pictq_mutex;  
  84.     SDL_cond        *pictq_cond;  
  85.       
  86.     SDL_Thread      *parse_tid;  
  87.     SDL_Thread      *video_tid;  
  88.       
  89.     char            filename[1024];  
  90.     int             quit;  
  91.       
  92.     AVIOContext     *io_context;  
  93.     struct SwsContext *sws_ctx;  
  94. } VideoState;  
  95.   
  96.   
  97.   
  98. /* Since we only have one decoding thread, the Big Struct 
  99.  can be global in case we need it. */  
  100. VideoState *global_video_state;  
  101.   
  102.   
  103.   
  104. void packet_queue_init(PacketQueue *q) {  
  105.     memset(q, 0, sizeof(PacketQueue));  
  106.     q->mutex = SDL_CreateMutex();  
  107.     q->cond = SDL_CreateCond();  
  108. }  
  109. int packet_queue_put(PacketQueue *q, AVPacket *pkt) {  
  110.       
  111.     AVPacketList *pkt1;  
  112.     if(av_dup_packet(pkt) < 0) {  
  113.         return -1;  
  114.     }  
  115.     pkt1 = av_malloc(sizeof(AVPacketList));  
  116.     if (!pkt1)  
  117.         return -1;  
  118.     pkt1->pkt = *pkt;  
  119.     pkt1->next = NULL;  
  120.       
  121.     SDL_LockMutex(q->mutex);  
  122.       
  123.     if (!q->last_pkt)  
  124.         q->first_pkt = pkt1;  
  125.     else  
  126.         q->last_pkt->next = pkt1;  
  127.     q->last_pkt = pkt1;  
  128.     q->nb_packets++;  
  129.     q->size += pkt1->pkt.size;  
  130.     SDL_CondSignal(q->cond);  
  131.       
  132.     SDL_UnlockMutex(q->mutex);  
  133.     return 0;  
  134. }  
  135. static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)  
  136. {  
  137.     AVPacketList *pkt1;  
  138.     int ret;  
  139.       
  140.     SDL_LockMutex(q->mutex);  
  141.       
  142.     for(;;) {  
  143.           
  144.         if(global_video_state->quit) {  
  145.             ret = -1;  
  146.             break;  
  147.         }  
  148.           
  149.         pkt1 = q->first_pkt;  
  150.         if (pkt1) {  
  151.             q->first_pkt = pkt1->next;  
  152.             if (!q->first_pkt)  
  153.                 q->last_pkt = NULL;  
  154.             q->nb_packets--;  
  155.             q->size -= pkt1->pkt.size;  
  156.             *pkt = pkt1->pkt;  
  157.             av_free(pkt1);  
  158.             ret = 1;  
  159.             break;  
  160.         } else if (!block) {  
  161.             ret = 0;  
  162.             break;  
  163.         } else {  
  164.             SDL_CondWait(q->cond, q->mutex);  
  165.         }  
  166.     }  
  167.     SDL_UnlockMutex(q->mutex);  
  168.     return ret;  
  169. }  
  170.   
  171. int audio_decode_frame(VideoState *is) {  
  172.     int len1, data_size = 0;  
  173.     AVPacket *pkt = &is->audio_pkt;  
  174.       
  175.     for(;;) {  
  176.         while(is->audio_pkt_size > 0) {  
  177.             int got_frame = 0;  
  178.             len1 = avcodec_decode_audio4(is->audio_st->codec, &is->audio_frame, &got_frame, pkt);  
  179.             if(len1 < 0) {  
  180.                 /* if error, skip frame */  
  181.                 is->audio_pkt_size = 0;  
  182.                 break;  
  183.             }  
  184.             if (got_frame)  
  185.             {  
  186.                 data_size =  
  187.                 av_samples_get_buffer_size  
  188.                 (  
  189.                  NULL,  
  190.                  is->audio_st->codec->channels,  
  191.                  is->audio_frame.nb_samples,  
  192.                  is->audio_st->codec->sample_fmt,  
  193.                  1  
  194.                  );  
  195.                 memcpy(is->audio_buf, is->audio_frame.data[0], data_size);  
  196.             }  
  197.             is->audio_pkt_data += len1;  
  198.             is->audio_pkt_size -= len1;  
  199.             if(data_size <= 0) {  
  200.                 /* No data yet, get more frames */  
  201.                 continue;  
  202.             }  
  203.             /* We have data, return it and come back for more later */  
  204.             return data_size;  
  205.         }  
  206.         if(pkt->data)  
  207.             av_free_packet(pkt);  
  208.           
  209.         if(is->quit) {  
  210.             return -1;  
  211.         }  
  212.         /* next packet */  
  213.         if(packet_queue_get(&is->audioq, pkt, 1) < 0) {  
  214.             return -1;  
  215.         }  
  216.         is->audio_pkt_data = pkt->data;  
  217.         is->audio_pkt_size = pkt->size;  
  218.     }  
  219. }  
  220.   
  221. void audio_callback(void *userdata, Uint8 *stream, int len) {  
  222.       
  223.     VideoState *is = (VideoState *)userdata;  
  224.     int len1, audio_size;  
  225.       
  226.     while(len > 0) {  
  227.         if(is->audio_buf_index >= is->audio_buf_size) {  
  228.             /* We have already sent all our data; get more */  
  229.             audio_size = audio_decode_frame(is);  
  230.             if(audio_size < 0) {  
  231.                 /* If error, output silence */  
  232.                 is->audio_buf_size = 1024;  
  233.                 memset(is->audio_buf, 0, is->audio_buf_size);  
  234.             } else {  
  235.                 is->audio_buf_size = audio_size;  
  236.             }  
  237.             is->audio_buf_index = 0;  
  238.         }  
  239.         len1 = is->audio_buf_size - is->audio_buf_index;  
  240.         if(len1 > len)  
  241.             len1 = len;  
  242.         memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);  
  243.         len -= len1;  
  244.         stream += len1;  
  245.         is->audio_buf_index += len1;  
  246.     }  
  247. }  
  248.   
  249. static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) {  
  250.     SDL_Event event;  
  251.     event.type = FF_REFRESH_EVENT;  
  252.     event.user.data1 = opaque;  
  253.     SDL_PushEvent(&event);  
  254.     return 0; /* 0 means stop timer */  
  255. }  
  256.   
  257. /* schedule a video refresh in 'delay' ms */  
  258. static void schedule_refresh(VideoState *is, int delay) {  
  259.     SDL_AddTimer(delay, sdl_refresh_timer_cb, is);  
  260. }  
  261.   
  262. void video_display(VideoState *is,SDL_Renderer* renderer,SDL_Texture* texture) {  
  263.       
  264.     SDL_Rect rect;  
  265.     VideoPicture *vp;  
  266.     //AVPicture pict;  
  267.     float aspect_ratio;  
  268.     //int w=0, h=0, x=0, y=0;  
  269.     //screen->w;  
  270.     //int i;  
  271.       
  272.     //renderer->w;  
  273.       
  274.     vp = &is->pictq[is->pictq_rindex];  
  275.     if(vp->rawdata) {  
  276.         if(is->video_st->codec->sample_aspect_ratio.num == 0) {  
  277.             aspect_ratio = 0;  
  278.         } else {  
  279.             aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio) *  
  280.             is->video_st->codec->width / is->video_st->codec->height;  
  281.         }  
  282.         if(aspect_ratio <= 0.0) {  
  283.             aspect_ratio = (float)is->video_st->codec->width /  
  284.             (float)is->video_st->codec->height;  
  285.         }  
  286.         //screen->h;  
  287. //        h = screen->h;  
  288. //        w = ((int)rint(h * aspect_ratio)) & -3;  
  289. //        if(w > screen->w) {  
  290. //            w = screen->w;  
  291. //            h = ((int)rint(w / aspect_ratio)) & -3;  
  292. //        }  
  293. //        x = (screen->w - w) / 2;  
  294. //        y = (screen->h - h) / 2;  
  295.           
  296.         rect.x = 0;  
  297.         rect.y = 0;  
  298.         rect.w = vp->width;  
  299.         rect.h = vp->height;  
  300.           
  301.         //SDL_SetRenderDrawColor(renderer, 120, 0, 0, 255);  
  302.         //SDL_RenderFillRect(renderer, &rect);  
  303.           
  304.         SDL_UpdateTexture( texture, &rect, vp->rawdata->data[0], vp->rawdata->linesize[0] );  
  305.         SDL_RenderClear( renderer );  
  306.         SDL_RenderCopy( renderer,texture , &rect, &rect );  
  307.         SDL_RenderPresent( renderer );  
  308.           
  309.         //SDL_DisplayYUVOverlay(vp->bmp, &rect);  
  310.     }  
  311. }  
  312.   
  313. void video_refresh_timer(void *userdata,SDL_Renderer* renderer,SDL_Texture* texture) {  
  314.       
  315.     VideoState *is = (VideoState *)userdata;  
  316.     // vp is used in later tutorials for synchronization  
  317.     //VideoPicture *vp;  
  318.       
  319.     if(is->video_st) {  
  320.         if(is->pictq_size == 0) {  
  321.             schedule_refresh(is, 1);  
  322.         } else {  
  323.             //vp = &is->pictq[is->pictq_rindex];  
  324.             /* Now, normally here goes a ton of code 
  325.              about timing, etc. we're just going to 
  326.              guess at a delay for now. You can 
  327.              increase and decrease this value and hard code 
  328.              the timing - but I don't suggest that ;) 
  329.              We'll learn how to do it for real later. 
  330.              */  
  331.             schedule_refresh(is, 30);  
  332.               
  333.             /* show the picture! */  
  334.             video_display(is,renderer,texture);  
  335.               
  336.             /* update queue for next picture! */  
  337.             if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE) {  
  338.                 is->pictq_rindex = 0;  
  339.             }  
  340.             SDL_LockMutex(is->pictq_mutex);  
  341.             is->pictq_size--;  
  342.             SDL_CondSignal(is->pictq_cond);  
  343.             SDL_UnlockMutex(is->pictq_mutex);  
  344.         }  
  345.     } else {  
  346.         schedule_refresh(is, 100);  
  347.     }  
  348. }  
  349.   
  350. void alloc_picture(void *userdata,SDL_Renderer* renderer) {  
  351.       
  352.     VideoState *is = (VideoState *)userdata;  
  353.     VideoPicture *vp;  
  354.       
  355.     vp = &is->pictq[is->pictq_windex];  
  356.     if(vp->rawdata) {  
  357.         // we already have one make another, bigger/smaller  
  358.         //SDL_DestroyTexture(vp->texture);  
  359.         //vp->texture = NULL;  
  360.         av_free(vp->rawdata);  
  361.         //SDL_FreeYUVOverlay(vp->bmp);  
  362.     }  
  363.     // Allocate a place to put our YUV image on that screen  
  364. //    vp->texture = SDL_CreateYUVOverlay(is->video_st->codec->width,  
  365. //                                   is->video_st->codec->height,  
  366. //                                   SDL_YV12_OVERLAY,  
  367. //                                   screen);  
  368.       
  369.       
  370.     vp->width = is->video_st->codec->width;  
  371.     vp->height = is->video_st->codec->height;  
  372.       
  373.       
  374.     AVCodecContext *pCodecCtx = NULL;  
  375.     pCodecCtx = is->video_st->codec;  
  376.       
  377.     AVFrame* pFrameYUV = avcodec_alloc_frame();  
  378.     if( pFrameYUV == NULL )  
  379.         return;  
  380.     int numBytes = avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width,  
  381.                                       pCodecCtx->height);  
  382.     uint8_t* buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));  
  383.       
  384.     avpicture_fill((AVPicture *)pFrameYUV, buffer, PIX_FMT_YUV420P,  
  385.                    pCodecCtx->width, pCodecCtx->height);  
  386.       
  387.       
  388.     vp->rawdata = pFrameYUV;  
  389.       
  390.     //SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, vp->width, vp->height);  
  391.       
  392.     SDL_LockMutex(is->pictq_mutex);  
  393.     vp->allocated = 1;  
  394.     SDL_CondSignal(is->pictq_cond);  
  395.     SDL_UnlockMutex(is->pictq_mutex);  
  396.       
  397. }  
  398.   
  399. int queue_picture(VideoState *is, AVFrame *pFrame) {  
  400.       
  401.     VideoPicture *vp;  
  402.     //AVCodecContext *pCodecCtx;  
  403.       
  404.       
  405.       
  406.       
  407.     /* wait until we have space for a new pic */  
  408.     SDL_LockMutex(is->pictq_mutex);  
  409.     while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&  
  410.           !is->quit) {  
  411.         SDL_CondWait(is->pictq_cond, is->pictq_mutex);  
  412.     }  
  413.     SDL_UnlockMutex(is->pictq_mutex);  
  414.       
  415.     if(is->quit)  
  416.         return -1;  
  417.       
  418.     // windex is set to 0 initially  
  419.     vp = &is->pictq[is->pictq_windex];  
  420.       
  421.     /* allocate or resize the buffer! */  
  422.     if(!vp->rawdata ||  
  423.        vp->width != is->video_st->codec->width ||  
  424.        vp->height != is->video_st->codec->height) {  
  425.         SDL_Event event;  
  426.           
  427.         vp->allocated = 0;  
  428.         /* we have to do it in the main thread */  
  429.         event.type = FF_ALLOC_EVENT;  
  430.         event.user.data1 = is;  
  431.         SDL_PushEvent(&event);  
  432.           
  433.         /* wait until we have a picture allocated */  
  434.         SDL_LockMutex(is->pictq_mutex);  
  435.         while(!vp->allocated && !is->quit) {  
  436.             SDL_CondWait(is->pictq_cond, is->pictq_mutex);  
  437.         }  
  438.         SDL_UnlockMutex(is->pictq_mutex);  
  439.         if(is->quit) {  
  440.             return -1;  
  441.         }  
  442.     }  
  443.       
  444.       
  445.       
  446.       
  447.     /* We have a place to put our picture on the queue */  
  448.       
  449.     if(vp->rawdata) {  
  450.           
  451.         //SDL_LockYUVOverlay(vp->bmp);  
  452.           
  453.         /* point pict at the queue */  
  454.           
  455. //        pict.data[0] = vp->bmp->pixels[0];  
  456. //        pict.data[1] = vp->bmp->pixels[2];  
  457. //        pict.data[2] = vp->bmp->pixels[1];  
  458. //          
  459. //        pict.linesize[0] = vp->bmp->pitches[0];  
  460. //        pict.linesize[1] = vp->bmp->pitches[2];  
  461. //        pict.linesize[2] = vp->bmp->pitches[1];  
  462.           
  463.         // Convert the image into YUV format that SDL uses  
  464.         sws_scale  
  465.         (  
  466.          is->sws_ctx,  
  467.          (uint8_t const * const *)pFrame->data,  
  468.          pFrame->linesize,  
  469.          0,  
  470.          is->video_st->codec->height,  
  471.          vp->rawdata->data,  
  472.          vp->rawdata->linesize  
  473.          );  
  474. //        SDL_Rect rect;  
  475. //        rect.x = 0;  
  476. //        rect.y = 0;  
  477. //        rect.w = vp->width;  
  478. //        rect.h = vp->height;  
  479.         //printf("%d,%d\n",rect.w,rect.h);  
  480.           
  481.         //SDL_UpdateTexture( vp->texture, &rect, pFrameYUV->data[0], pFrameYUV->linesize[0] );  
  482.           
  483.         //av_free(pFrameYUV);  
  484.           
  485.         //SDL_UnlockYUVOverlay(vp->bmp);  
  486.         /* now we inform our display thread that we have a pic ready */  
  487.         if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE) {  
  488.             is->pictq_windex = 0;  
  489.         }  
  490.         SDL_LockMutex(is->pictq_mutex);  
  491.         is->pictq_size++;  
  492.         SDL_UnlockMutex(is->pictq_mutex);  
  493.     }  
  494.     return 0;  
  495. }  
  496.   
  497. int video_thread(void *arg) {  
  498.     VideoState *is = (VideoState *)arg;  
  499.     AVPacket pkt1, *packet = &pkt1;  
  500.     int frameFinished;  
  501.     AVFrame *pFrame;  
  502.       
  503.     pFrame = avcodec_alloc_frame();  
  504.       
  505.     for(;;) {  
  506.         if(packet_queue_get(&is->videoq, packet, 1) < 0) {  
  507.             // means we quit getting packets  
  508.             break;  
  509.         }  
  510.         // Decode video frame  
  511.         avcodec_decode_video2(is->video_st->codec, pFrame, &frameFinished,  
  512.                               packet);  
  513.           
  514.         // Did we get a video frame?  
  515.         if(frameFinished) {  
  516.             //printf("video_thread\n");  
  517.             if(queue_picture(is, pFrame) < 0) {  
  518.                 break;  
  519.             }  
  520.         }  
  521.         av_free_packet(packet);  
  522.     }  
  523.     av_free(pFrame);  
  524.     return 0;  
  525. }  
  526.   
  527. int stream_component_open(VideoState *is, int stream_index) {  
  528.       
  529.     AVFormatContext *pFormatCtx = is->pFormatCtx;  
  530.     AVCodecContext *codecCtx = NULL;  
  531.     AVCodec *codec = NULL;  
  532.     AVDictionary *optionsDict = NULL;  
  533.     SDL_AudioSpec wanted_spec, spec;  
  534.       
  535.     if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams) {  
  536.         return -1;  
  537.     }  
  538.       
  539.     // Get a pointer to the codec context for the video stream  
  540.     codecCtx = pFormatCtx->streams[stream_index]->codec;  
  541.       
  542.     if(codecCtx->codec_type == AVMEDIA_TYPE_AUDIO) {  
  543.         // Set audio settings from codec info  
  544.         wanted_spec.freq = codecCtx->sample_rate;  
  545.         wanted_spec.format = AUDIO_S16SYS;  
  546.         wanted_spec.channels = codecCtx->channels;  
  547.         wanted_spec.silence = 0;  
  548.         wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;  
  549.         wanted_spec.callback = audio_callback;  
  550.         wanted_spec.userdata = is;  
  551.           
  552.         if(SDL_OpenAudio(&wanted_spec, &spec) < 0) {  
  553.             fprintf(stderr, "SDL_OpenAudio: %s\n", SDL_GetError());  
  554.             return -1;  
  555.         }  
  556.     }  
  557.     codec = avcodec_find_decoder(codecCtx->codec_id);  
  558.     if(!codec || (avcodec_open2(codecCtx, codec, &optionsDict) < 0)) {  
  559.         fprintf(stderr, "Unsupported codec!\n");  
  560.         return -1;  
  561.     }  
  562.       
  563.     switch(codecCtx->codec_type) {  
  564.         case AVMEDIA_TYPE_AUDIO:  
  565.             is->audioStream = stream_index;  
  566.             is->audio_st = pFormatCtx->streams[stream_index];  
  567.             is->audio_buf_size = 0;  
  568.             is->audio_buf_index = 0;  
  569.             memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));  
  570.             packet_queue_init(&is->audioq);  
  571.             SDL_PauseAudio(0);  
  572.             break;  
  573.         case AVMEDIA_TYPE_VIDEO:  
  574.             is->videoStream = stream_index;  
  575.             is->video_st = pFormatCtx->streams[stream_index];  
  576.               
  577.             packet_queue_init(&is->videoq);  
  578.             is->video_tid = SDL_CreateThread(video_thread, "video_thread",is);  
  579.             is->sws_ctx =  
  580.             sws_getContext  
  581.             (  
  582.              is->video_st->codec->width,  
  583.              is->video_st->codec->height,  
  584.              is->video_st->codec->pix_fmt,  
  585.              is->video_st->codec->width,  
  586.              is->video_st->codec->height,  
  587.              PIX_FMT_YUV420P,  
  588.              SWS_BILINEAR,  
  589.              NULL,  
  590.              NULL,  
  591.              NULL  
  592.              );  
  593.             break;  
  594.         default:  
  595.             break;  
  596.     }  
  597.     return 0;  
  598. }  
  599.   
  600. int decode_interrupt_cb(void *opaque) {  
  601.     return (global_video_state && global_video_state->quit);  
  602. }  
  603.   
  604. int decode_thread(void *arg) {  
  605.       
  606.     VideoState *is = (VideoState *)arg;  
  607.     AVFormatContext *pFormatCtx = NULL;  
  608.     AVPacket pkt1, *packet = &pkt1;  
  609.       
  610.     int video_index = -1;  
  611.     int audio_index = -1;  
  612.     int i;  
  613.       
  614.     AVDictionary *io_dict = NULL;  
  615.     AVIOInterruptCB callback;  
  616.       
  617.     is->videoStream=-1;  
  618.     is->audioStream=-1;  
  619.       
  620.     global_video_state = is;  
  621.     // will interrupt blocking functions if we quit!  
  622.     callback.callback = decode_interrupt_cb;  
  623.     callback.opaque = is;  
  624.     if (avio_open2(&is->io_context, is->filename, 0, &callback, &io_dict))  
  625.     {  
  626.         fprintf(stderr, "Unable to open I/O for %s\n", is->filename);  
  627.         return -1;  
  628.     }  
  629.       
  630.     // Open video file  
  631.     if(avformat_open_input(&pFormatCtx, is->filename, NULL, NULL)!=0)  
  632.         return -1; // Couldn't open file  
  633.       
  634.     is->pFormatCtx = pFormatCtx;  
  635.       
  636.     // Retrieve stream information  
  637.     if(avformat_find_stream_info(pFormatCtx, NULL)<0)  
  638.         return -1; // Couldn't find stream information  
  639.       
  640.     // Dump information about file onto standard error  
  641.     av_dump_format(pFormatCtx, 0, is->filename, 0);  
  642.       
  643.     // Find the first video stream  
  644.       
  645.     for(i=0; i<pFormatCtx->nb_streams; i++) {  
  646.         if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO &&  
  647.            video_index < 0) {  
  648.             video_index=i;  
  649.         }  
  650.         if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO &&  
  651.            audio_index < 0) {  
  652.             audio_index=i;  
  653.         }  
  654.     }  
  655.     if(audio_index >= 0) {  
  656.         stream_component_open(is, audio_index);  
  657.     }  
  658.     if(video_index >= 0) {  
  659.         stream_component_open(is, video_index);  
  660.     }  
  661.       
  662.     if(is->videoStream < 0 || is->audioStream < 0) {  
  663.         fprintf(stderr, "%s: could not open codecs\n", is->filename);  
  664.         goto fail;  
  665.     }  
  666.       
  667.     // main decode loop  
  668.       
  669.     for(;;) {  
  670.         if(is->quit) {  
  671.             break;  
  672.         }  
  673.         // seek stuff goes here  
  674.         if(is->audioq.size > MAX_AUDIOQ_SIZE ||  
  675.            is->videoq.size > MAX_VIDEOQ_SIZE) {  
  676.             SDL_Delay(10);  
  677.             continue;  
  678.         }  
  679.         if(av_read_frame(is->pFormatCtx, packet) < 0) {  
  680.             if(is->pFormatCtx->pb->error == 0) {  
  681.                 SDL_Delay(100); /* no error; wait for user input */  
  682.                 continue;  
  683.             } else {  
  684.                 break;  
  685.             }  
  686.         }  
  687.         // Is this a packet from the video stream?  
  688.         if(packet->stream_index == is->videoStream) {  
  689.             packet_queue_put(&is->videoq, packet);  
  690.         } else if(packet->stream_index == is->audioStream) {  
  691.             packet_queue_put(&is->audioq, packet);  
  692.         } else {  
  693.             av_free_packet(packet);  
  694.         }  
  695.     }  
  696.     /* all done - wait for it */  
  697.     while(!is->quit) {  
  698.         SDL_Delay(100);  
  699.     }  
  700.       
  701. fail:  
  702.     if(1){  
  703.         SDL_Event event;  
  704.         event.type = FF_QUIT_EVENT;  
  705.         event.user.data1 = is;  
  706.         SDL_PushEvent(&event);  
  707.     }  
  708.     return 0;  
  709. }  
  710.   
  711. int main(int argc, char *argv[]) {  
  712.       
  713.     SDL_Event       event;  
  714.       
  715.     VideoState      *is;  
  716.       
  717.     struct SDL_Window     *pScreen;  
  718.     struct SDL_Renderer   *pRenderer;  
  719.       
  720.       
  721.     is = av_mallocz(sizeof(VideoState));  
  722.       
  723.     if(argc < 2) {  
  724.         fprintf(stderr, "Usage: test <file>\n");  
  725.         exit(1);  
  726.     }  
  727.     // Register all formats and codecs  
  728.     av_register_all();  
  729.       
  730.     if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {  
  731.         fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());  
  732.         exit(1);  
  733.     }  
  734.       
  735.     // Make a screen to put our video  
  736. //#ifndef __DARWIN__  
  737. //    screen = SDL_SetVideoMode(640, 480, 0, 0);  
  738. //#else  
  739. //    screen = SDL_SetVideoMode(640, 480, 24, 0);  
  740. //#endif  
  741.       
  742.     pScreen = SDL_CreateWindow("audio & video", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 672,376, SDL_WINDOW_OPENGL);  
  743.       
  744.     if(!pScreen) {  
  745.         fprintf(stderr, "SDL: could not set video mode - exiting\n");  
  746.         exit(1);  
  747.     }  
  748.     //SDL_Window *windows = pScreen;  
  749.       
  750.     //pScreen->windowed;  
  751.     pRenderer = SDL_CreateRenderer(pScreen, -1, 0);  
  752.       
  753.     SDL_Texture* texture = SDL_CreateTexture(pRenderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, 672, 376);  
  754.       
  755.       
  756.     av_strlcpy(is->filename, argv[1], 1024);  
  757.       
  758.     is->pictq_mutex = SDL_CreateMutex();  
  759.     is->pictq_cond = SDL_CreateCond();  
  760.       
  761.     schedule_refresh(is, 40);  
  762.       
  763.     is->parse_tid = SDL_CreateThread(decode_thread,"parse_thread", is);  
  764.     if(!is->parse_tid) {  
  765.         av_free(is);  
  766.         return -1;  
  767.     }  
  768.     for(;;) {  
  769.           
  770.         SDL_WaitEvent(&event);  
  771.         switch(event.type) {  
  772.             case FF_QUIT_EVENT:  
  773.             case SDL_QUIT:  
  774.                 is->quit = 1;  
  775.                 /* 
  776.                  * If the video has finished playing, then both the picture and 
  777.                  * audio queues are waiting for more data.  Make them stop 
  778.                  * waiting and terminate normally. 
  779.                  */  
  780.                 SDL_CondSignal(is->audioq.cond);  
  781.                 SDL_CondSignal(is->videoq.cond);  
  782.                 SDL_Quit();  
  783.                 return 0;  
  784.                 break;  
  785.             case FF_ALLOC_EVENT:  
  786.                 alloc_picture(event.user.data1,pRenderer);  
  787.                 break;  
  788.             case FF_REFRESH_EVENT:  
  789.                 video_refresh_timer(event.user.data1,pRenderer,texture);  
  790.                 break;  
  791.             default:  
  792.                 break;  
  793.         }  
  794.     }  
  795.       
  796.     SDL_DestroyTexture(texture);  
  797.       
  798.     return 0;  
  799.       
  800. }  

这段代码的总体思路是跑一个parse线程解包,当解析到音频包时放入音频队列,当解析到视频包时放入视频队列,

当接到有视频包后,起一个线程用来解码视频包,解码完调用事件让主线程显示解码完的数据包



注意点

opengl相关操作需要在主线程中进行,比如SDL_UpdateTexture函数。

在我修改int queue_picture(VideoState *is,AVFrame *pFrame)代码时,误将SDL_Texure在此函数中写入数据

导致程序运行到SDL_UpdateTexture( vp->texture, &rect, pFrameYUV->data[0], pFrameYUV->linesize[0] );

后renderdata->glEnable(data->type);处报错,报bad_access,起先以为是pFrameYUV为空指针,后四处排查也找不到原因

突然想起opengl的操作是不是需要在主线程中进行?

后来我将SDL_UpdateTexture操作放置到video_display函数中,问题解决。


运行结果



引用库如下




结束语

2013年最后半小时了,本命年还算顺利

可喜的是这一年技术接触面很广,学会了ios开发,android水平有进阶,c/c++水平有提高,设计模式提高不少

可悲的是阿里前端实习被刷(死的很惨),论文毫无进展,老板要我搞云计算

最后感谢朱阿姝同学的陪伴

希望明年可以顺利完成论文,在github上多贡献几个项目攒人品,父母身体健康

0 0
原创粉丝点击