首页 > 代码库 > ffmpeg+sdl教程----编写一个简单的播放器5(同步视频到音频)

ffmpeg+sdl教程----编写一个简单的播放器5(同步视频到音频)

来源:http://blog.csdn.net/mu399/article/details/5816566

   个人认为,这这部分教程的新增代码量虽然不是最多的,难度却是最大的,重复看了多次才明白,因为有两个问题的困扰,搞得还不清楚:

1.音频和视频既然都有各自的时间戳,各自按各自的时间戳来播放不就行了,为什么还需要同步呢?

2.如果要把视频同步到音频,怎么同步?或者说以什么标准来同步?

    第一个问题的答案可能是,一是音频和视频的开始播放的时间是不一样,二是播放每帧音频或视频时可能必须把解码数据,视频格式转换消耗的时间考虑进来,解码 数据,视频格式转换等步骤又和不同的机器配置相关,设想一下这种极端的情况,有一帧图片应该在此时刻播放了(根据时间戳),而解码器还没来及解码完(程序 代码或者机器配置太烂),解码完后,可能需要丢弃该帧,不然视频赶不上音频。

    第二个问题的答案也不是很清楚,但根据这个教程的代码来分析,特别是video_refresh_timer函数中关于时间戳部分的代码告诉了这个问题答 案,首先大结构体VideoState保存了两个用于同步的两个重要变量audio_clock和video_clock,分别保存了音频和视频的播放了 多长时间,也就是教程中说的音频和视频的内部时钟。把视频同步到音频的方法就是比较video_clock(当前视频播放到的时刻)和 audio_clock(当前音频播放到的时刻)差的绝对值如果大于同步阈值sync_threshold,就重新计算延迟delay,这时视频如果播放 得太快就直接让延迟delay = 2*delay,反之则立即播放。而video_clock和audio_clock之差在可接受范围内,delay的值直接取上一帧和当前帧的延 迟,delay将被用于下一帧的播放延迟。

    时钟的同步,教程中分为三个部分。

    第一部分讲如何保存视频帧的时间戳和video_clock,代码主要在video_thread函数中,该函数中的这行代码len1 = avcodec_decode_video(is->video_st->codec, pFrame, &frameFinished,packet->data, packet->size);解码packet中的数据到pFrame时,会调用我们自己些的帧内存分配函数our_get_buffer,把第一 个包的时间戳保存到帧pFrame中(一个帧可能由多个数据包组成),帧的时间戳优先取最后一个包的dts,没有才取第一个包的pts,都没有就取 video_clock。

   video_thread函数在解码完一帧后,立马调用synchronize_video函数,synchronize_video函数的作用就是维护 video_clock的值,让video_clock变量始终保存视频播放了多长时间的信息,其中还考虑到了帧重复的问题。得到当前视频帧的时间戳相对 音频来说简单些。

    第二部分讲,假设我们能得到当前音频的时间戳,如何让视频同步到音频,也就是上面第二个问题的答案。

    第三部分讲如何获得当前音频帧的时间戳,代码主要在get_audio_clock函数中,这个并不是简单地返回is->audio_clock了 事,如果那样做就忽略了把数据包转移到输出缓冲的时间花费,我们声音时钟中记录的时间比实际的要早太多。所以我们必须要检查一下我们还有多少没有写入。 audio_clock的维护工作交给了audio_decode_frame函数来处理,首先在函数末尾初始化is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;然后解码完一帧音频后又有更新。

   

 

[cpp] view plaincopy
  1. // tutorial05.c  
  2. // A pedagogical video player that really works!  
  3. //  
  4. // Code based on FFplay, Copyright (c) 2003 Fabrice Bellard,  
  5. // and a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)  
  6. // Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1  
  7. // Use  
  8. //  
  9. // gcc -o tutorial05 tutorial05.c -lavformat -lavcodec -lz -lm `sdl-config --cflags --libs`  
  10. // to build (assuming libavformat and libavcodec are correctly installed,  
  11. // and assuming you have sdl-config. Please refer to SDL docs for your installation.)  
  12. //  
  13. // Run using  
  14. // tutorial05 myvideofile.mpg  
  15. //  
  16. // to play the video.  
  17.   
  18. #include "libavformat/avformat.h"  
  19. #include "libswscale/swscale.h"  
  20.   
  21. #include <SDL/SDL.h>  
  22. #include <SDL/SDL_thread.h>  
  23.   
  24. #ifdef main  
  25. #undef main /* Prevents SDL from overriding main() */  
  26. #endif  
  27.   
  28. #include <stdio.h>  
  29. #include <math.h>  
  30.   
  31. #define SDL_AUDIO_BUFFER_SIZE 1024  
  32.   
  33. #define MAX_AUDIOQ_SIZE (5 * 16 * 1024)  
  34. #define MAX_VIDEOQ_SIZE (5 * 256 * 1024)  
  35.   
  36. #define AV_SYNC_THRESHOLD 0.01  
  37. #define AV_NOSYNC_THRESHOLD 10.0  
  38.   
  39. #define FF_ALLOC_EVENT   (SDL_USEREVENT)  
  40. #define FF_REFRESH_EVENT (SDL_USEREVENT + 1)  
  41. #define FF_QUIT_EVENT (SDL_USEREVENT + 2)  
  42.   
  43. #define VIDEO_PICTURE_QUEUE_SIZE 1  
  44.   
  45. typedef struct PacketQueue  
  46. {  
  47.     AVPacketList *first_pkt, *last_pkt;  
  48.     int nb_packets;  
  49.     int size;  
  50.     SDL_mutex *mutex;  
  51.     SDL_cond *cond;  
  52. } PacketQueue;  
  53.   
  54. typedef struct VideoPicture  
  55. {  
  56.     SDL_Overlay *bmp;  
  57.     int width, height; /* source height & width */  
  58.     int allocated;  
  59.     double pts;  
  60. } VideoPicture;  
  61.   
  62. typedef struct VideoState  
  63. {  
  64.     AVFormatContext *pFormatCtx;  
  65.     int             videoStream, audioStream;  
  66.     double          audio_clock;  
  67.     AVStream        *audio_st;  
  68.     PacketQueue     audioq;  
  69.     uint8_t         audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];  
  70.     unsigned int    audio_buf_size;  
  71.     unsigned int    audio_buf_index;  
  72.     AVPacket        audio_pkt;  
  73.     uint8_t         *audio_pkt_data;  
  74.     int             audio_pkt_size;  
  75.     int             audio_hw_buf_size;  
  76.     double          frame_timer;  
  77.     double          frame_last_pts;  
  78.     double          frame_last_delay;  
  79.     double          video_clock; ///<pts of last decoded frame / predicted pts of next decoded frame  
  80.     AVStream        *video_st;  
  81.     PacketQueue     videoq;  
  82.   
  83.     VideoPicture    pictq[VIDEO_PICTURE_QUEUE_SIZE];  
  84.     int             pictq_size, pictq_rindex, pictq_windex;  
  85.     SDL_mutex       *pictq_mutex;  
  86.     SDL_cond        *pictq_cond;  
  87.     SDL_Thread      *parse_tid;  
  88.     SDL_Thread      *video_tid;  
  89.   
  90.     char            filename[1024];  
  91.     int             quit;  
  92. } VideoState;  
  93.   
  94. SDL_Surface     *screen;  
  95.   
  96. /* Since we only have one decoding thread, the Big Struct 
  97. can be global in case we need it. */  
  98. VideoState *global_video_state;  
  99.   
  100. void packet_queue_init(PacketQueue *q)  
  101. {  
  102.     memset(q, 0, sizeof(PacketQueue));  
  103.     q->mutex = SDL_CreateMutex();  
  104.     q->cond = SDL_CreateCond();  
  105. }  
  106. int packet_queue_put(PacketQueue *q, AVPacket *pkt)  
  107. {  
  108.     AVPacketList *pkt1;  
  109.     if(av_dup_packet(pkt) < 0)  
  110.     {  
  111.         return -1;  
  112.     }  
  113.     pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList));  
  114.     if (!pkt1)  
  115.         return -1;  
  116.     pkt1->pkt = *pkt;  
  117.     pkt1->next = NULL;  
  118.   
  119.     SDL_LockMutex(q->mutex);  
  120.   
  121.     if (!q->last_pkt)  
  122.         q->first_pkt = pkt1;  
  123.     else  
  124.         q->last_pkt->next = pkt1;  
  125.     q->last_pkt = pkt1;  
  126.     q->nb_packets++;  
  127.     q->size += pkt1->pkt.size;  
  128.     SDL_CondSignal(q->cond);  
  129.   
  130.     SDL_UnlockMutex(q->mutex);  
  131.     return 0;  
  132. }  
  133.   
  134. static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)  
  135. {  
  136.     AVPacketList *pkt1;  
  137.     int ret;  
  138.   
  139.     SDL_LockMutex(q->mutex);  
  140.   
  141.     for(;;)  
  142.     {  
  143.         if(global_video_state->quit)  
  144.         {  
  145.             ret = -1;  
  146.             break;  
  147.         }  
  148.   
  149.         pkt1 = q->first_pkt;  
  150.         if (pkt1)  
  151.         {  
  152.             q->first_pkt = pkt1->next;  
  153.             if (!q->first_pkt)  
  154.                 q->last_pkt = NULL;  
  155.             q->nb_packets--;  
  156.             q->size -= pkt1->pkt.size;  
  157.             *pkt = pkt1->pkt;  
  158.             av_free(pkt1);  
  159.             ret = 1;  
  160.             break;  
  161.         }  
  162.         else if (!block)  
  163.         {  
  164.             ret = 0;  
  165.             break;  
  166.         }  
  167.         else  
  168.         {  
  169.             SDL_CondWait(q->cond, q->mutex);  
  170.         }  
  171.     }  
  172.     SDL_UnlockMutex(q->mutex);  
  173.     return ret;  
  174. }  
  175. double get_audio_clock(VideoState *is)  
  176. {  
  177.     double pts;  
  178.     int hw_buf_size, bytes_per_sec, n;  
  179.   
  180.     pts = is->audio_clock; /* maintained in the audio thread */  
  181.     hw_buf_size = is->audio_buf_size - is->audio_buf_index;  
  182.     bytes_per_sec = 0;  
  183.     n = is->audio_st->codec->channels * 2;  
  184.     if(is->audio_st)  
  185.     {  
  186.         bytes_per_sec = is->audio_st->codec->sample_rate * n;  
  187.     }  
  188.     if(bytes_per_sec)  
  189.     {  
  190.         pts -= (double)hw_buf_size / bytes_per_sec;  
  191.     }  
  192.     return pts;  
  193. }  
  194.   
  195. int audio_decode_frame(VideoState *is, uint8_t *audio_buf, int buf_size, double *pts_ptr)  
  196. {  
  197.     int len1, data_size, n;  
  198.     AVPacket *pkt = &is->audio_pkt;  
  199.     double pts;  
  200.   
  201.     for(;;)  
  202.     {  
  203.         while(is->audio_pkt_size > 0)  
  204.         {  
  205.             data_size = buf_size;  
  206.             len1 = avcodec_decode_audio2(is->audio_st->codec,  
  207.                                          (int16_t *)audio_buf, &data_size,  
  208.                                          is->audio_pkt_data, is->audio_pkt_size);  
  209.             if(len1 < 0)  
  210.             {  
  211.                 /* if error, skip frame */  
  212.                 is->audio_pkt_size = 0;  
  213.                 break;  
  214.             }  
  215.             is->audio_pkt_data += len1;  
  216.             is->audio_pkt_size -= len1;  
  217.             if(data_size <= 0)  
  218.             {  
  219.                 /* No data yet, get more frames */  
  220.                 continue;  
  221.             }  
  222.             pts = is->audio_clock;  
  223.             *pts_ptr = pts;  
  224.             n = 2 * is->audio_st->codec->channels;  
  225.             is->audio_clock += (double)data_size /  
  226.                                (double)(n * is->audio_st->codec->sample_rate);  
  227.   
  228.             /* We have data, return it and come back for more later */  
  229.             return data_size;  
  230.         }  
  231.         if(pkt->data)  
  232.             av_free_packet(pkt);  
  233.   
  234.         if(is->quit)  
  235.         {  
  236.             return -1;  
  237.         }  
  238.         /* next packet */  
  239.         if(packet_queue_get(&is->audioq, pkt, 1) < 0)  
  240.         {  
  241.             return -1;  
  242.         }  
  243.         is->audio_pkt_data = pkt->data;  
  244.         is->audio_pkt_size = pkt->size;  
  245.         /* if update, update the audio clock w/pts */  
  246.         if(pkt->pts != AV_NOPTS_VALUE)  
  247.         {  
  248.             is->audio_clock = av_q2d(is->audio_st->time_base)*pkt->pts;  
  249.         }  
  250.     }  
  251. }  
  252.   
  253. void audio_callback(void *userdata, Uint8 *stream, int len)  
  254. {  
  255.     VideoState *is = (VideoState *)userdata;  
  256.     int len1, audio_size;  
  257.     double pts;  
  258.   
  259.     while(len > 0)  
  260.     {  
  261.         if(is->audio_buf_index >= is->audio_buf_size)  
  262.         {  
  263.             /* We have already sent all our data; get more */  
  264.             audio_size = audio_decode_frame(is, is->audio_buf, sizeof(is->audio_buf), &pts);  
  265.             if(audio_size < 0)  
  266.             {  
  267.                 /* If error, output silence */  
  268.                 is->audio_buf_size = 1024;  
  269.                 memset(is->audio_buf, 0, is->audio_buf_size);  
  270.             }  
  271.             else  
  272.             {  
  273.                 is->audio_buf_size = audio_size;  
  274.             }  
  275.             is->audio_buf_index = 0;  
  276.         }  
  277.         len1 = is->audio_buf_size - is->audio_buf_index;  
  278.         if(len1 > len)  
  279.             len1 = len;  
  280.         memcpy(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1);  
  281.         len -= len1;  
  282.         stream += len1;  
  283.         is->audio_buf_index += len1;  
  284.     }  
  285. }  
  286.   
  287. static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque)  
  288. {  
  289.     SDL_Event event;  
  290.     event.type = FF_REFRESH_EVENT;  
  291.     event.user.data1 = opaque;  
  292.     SDL_PushEvent(&event);  
  293.     return 0; /* 0 means stop timer */  
  294. }  
  295.   
  296. /* schedule a video refresh in ‘delay‘ ms */  
  297. static void schedule_refresh(VideoState *is, int delay)  
  298. {  
  299.     SDL_AddTimer(delay, sdl_refresh_timer_cb, is);  
  300. }  
  301.   
  302. void video_display(VideoState *is)  
  303. {  
  304.     SDL_Rect rect;  
  305.     VideoPicture *vp;  
  306.     AVPicture pict;  
  307.     float aspect_ratio;  
  308.     int w, h, x, y;  
  309.     int i;  
  310.   
  311.     vp = &is->pictq[is->pictq_rindex];  
  312.     if(vp->bmp)  
  313.     {  
  314.         if(is->video_st->codec->sample_aspect_ratio.num == 0)  
  315.         {  
  316.             aspect_ratio = 0;  
  317.         }  
  318.         else  
  319.         {  
  320.             aspect_ratio = av_q2d(is->video_st->codec->sample_aspect_ratio) *  
  321.                            is->video_st->codec->width / is->video_st->codec->height;  
  322.         }  
  323.         if(aspect_ratio <= 0.0)  
  324.         {  
  325.             aspect_ratio = (float)is->video_st->codec->width /  
  326.                            (float)is->video_st->codec->height;  
  327.         }  
  328.         h = screen->h;  
  329.         w = ((int)(h * aspect_ratio)) & -3;  
  330.         if(w > screen->w)  
  331.         {  
  332.             w = screen->w;  
  333.             h = ((int)(w / aspect_ratio)) & -3;  
  334.         }  
  335.         x = (screen->w - w) / 2;  
  336.         y = (screen->h - h) / 2;  
  337.   
  338.         rect.x = x;  
  339.         rect.y = y;  
  340.         rect.w = w;  
  341.         rect.h = h;  
  342.         SDL_DisplayYUVOverlay(vp->bmp, &rect);  
  343.     }  
  344. }  
  345.   
  346. void video_refresh_timer(void *userdata)  
  347. {  
  348.     VideoState *is = (VideoState *)userdata;  
  349.     VideoPicture *vp;  
  350.     double actual_delay, delay, sync_threshold, ref_clock, diff;  
  351.   
  352.     if(is->video_st)  
  353.     {  
  354.         if(is->pictq_size == 0)  
  355.         {  
  356.             schedule_refresh(is, 1);  
  357.         }  
  358.         else  
  359.         {  
  360.             vp = &is->pictq[is->pictq_rindex];  
  361.   
  362.             delay = vp->pts - is->frame_last_pts; /* the pts from last time */  
  363.             if(delay <= 0 || delay >= 1.0)  
  364.             {  
  365.                 /* if incorrect delay, use previous one */  
  366.                 delay = is->frame_last_delay;  
  367.             }  
  368.             /* save for next time */  
  369.             is->frame_last_delay = delay;  
  370.             is->frame_last_pts = vp->pts;  
  371.   
  372.             /* update delay to sync to audio */  
  373.             ref_clock = get_audio_clock(is);  
  374.             diff = vp->pts - ref_clock;  
  375.   
  376.             /* Skip or repeat the frame. Take delay into account 
  377.             FFPlay still doesn‘t "know if this is the best guess." */  
  378.             sync_threshold = (delay > AV_SYNC_THRESHOLD) ? delay : AV_SYNC_THRESHOLD;  
  379.             if(fabs(diff) < AV_NOSYNC_THRESHOLD)  
  380.             {  
  381.                 if(diff <= -sync_threshold)  
  382.                 {  
  383.                     delay = 0;  
  384.                 }  
  385.                 else if(diff >= sync_threshold)  
  386.                 {  
  387.                     delay = 2 * delay;  
  388.                 }  
  389.             }  
  390.             is->frame_timer += delay;  
  391.             /* computer the REAL delay */  
  392.             actual_delay = is->frame_timer - (av_gettime() / 1000000.0);  
  393.             if(actual_delay < 0.010)  
  394.             {  
  395.                 /* Really it should skip the picture instead */  
  396.                 actual_delay = 0.010;  
  397.             }  
  398.             schedule_refresh(is, (int)(actual_delay * 1000 + 0.5));  
  399.             /* show the picture! */  
  400.             video_display(is);  
  401.   
  402.             /* update queue for next picture! */  
  403.             if(++is->pictq_rindex == VIDEO_PICTURE_QUEUE_SIZE)  
  404.             {  
  405.                 is->pictq_rindex = 0;  
  406.             }  
  407.             SDL_LockMutex(is->pictq_mutex);  
  408.             is->pictq_size--;  
  409.             SDL_CondSignal(is->pictq_cond);  
  410.             SDL_UnlockMutex(is->pictq_mutex);  
  411.         }  
  412.     }  
  413.     else  
  414.     {  
  415.         schedule_refresh(is, 100);  
  416.     }  
  417. }  
  418.   
  419. void alloc_picture(void *userdata)  
  420. {  
  421.     VideoState *is = (VideoState *)userdata;  
  422.     VideoPicture *vp;  
  423.   
  424.     vp = &is->pictq[is->pictq_windex];  
  425.     if(vp->bmp)  
  426.     {  
  427.         // we already have one make another, bigger/smaller  
  428.         SDL_FreeYUVOverlay(vp->bmp);  
  429.     }  
  430.     // Allocate a place to put our YUV image on that screen  
  431.     vp->bmp = SDL_CreateYUVOverlay(is->video_st->codec->width,  
  432.                                    is->video_st->codec->height,  
  433.                                    SDL_YV12_OVERLAY,  
  434.                                    screen);  
  435.     vp->width = is->video_st->codec->width;  
  436.     vp->height = is->video_st->codec->height;  
  437.   
  438.     SDL_LockMutex(is->pictq_mutex);  
  439.     vp->allocated = 1;  
  440.     SDL_CondSignal(is->pictq_cond);  
  441.     SDL_UnlockMutex(is->pictq_mutex);  
  442. }  
  443.   
  444. int queue_picture(VideoState *is, AVFrame *pFrame, double pts)  
  445. {  
  446.     VideoPicture *vp;  
  447.     //int dst_pix_fmt;  
  448.     AVPicture pict;  
  449.   
  450.     /* wait until we have space for a new pic */  
  451.     SDL_LockMutex(is->pictq_mutex);  
  452.     while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE &&  
  453.             !is->quit)  
  454.     {  
  455.         SDL_CondWait(is->pictq_cond, is->pictq_mutex);  
  456.     }  
  457.     SDL_UnlockMutex(is->pictq_mutex);  
  458.   
  459.     if(is->quit)  
  460.         return -1;  
  461.   
  462.     // windex is set to 0 initially  
  463.     vp = &is->pictq[is->pictq_windex];  
  464.   
  465.     /* allocate or resize the buffer! */  
  466.     if(!vp->bmp ||  
  467.             vp->width != is->video_st->codec->width ||  
  468.             vp->height != is->video_st->codec->height)  
  469.     {  
  470.         SDL_Event event;  
  471.   
  472.         vp->allocated = 0;  
  473.         /* we have to do it in the main thread */  
  474.         event.type = FF_ALLOC_EVENT;  
  475.         event.user.data1 = is;  
  476.         SDL_PushEvent(&event);  
  477.   
  478.         /* wait until we have a picture allocated */  
  479.         SDL_LockMutex(is->pictq_mutex);  
  480.         while(!vp->allocated && !is->quit)  
  481.         {  
  482.             SDL_CondWait(is->pictq_cond, is->pictq_mutex);  
  483.         }  
  484.         SDL_UnlockMutex(is->pictq_mutex);  
  485.         if(is->quit)  
  486.         {  
  487.             return -1;  
  488.         }  
  489.     }  
  490.     /* We have a place to put our picture on the queue */  
  491.     /* If we are skipping a frame, do we set this to null 
  492.     but still return vp->allocated = 1? */  
  493.     static struct SwsContext *img_convert_ctx;  
  494.     if (img_convert_ctx == NULL)  
  495.     {  
  496.         img_convert_ctx = sws_getContext(is->video_st->codec->width, is->video_st->codec->height,  
  497.                                          is->video_st->codec->pix_fmt,  
  498.                                          is->video_st->codec->width, is->video_st->codec->height,  
  499.                                          PIX_FMT_YUV420P,  
  500.                                          SWS_BICUBIC, NULL, NULL, NULL);  
  501.         if (img_convert_ctx == NULL)  
  502.         {  
  503.             fprintf(stderr, "Cannot initialize the conversion context/n");  
  504.             exit(1);  
  505.         }  
  506.     }  
  507.   
  508.     if(vp->bmp)  
  509.     {  
  510.         SDL_LockYUVOverlay(vp->bmp);  
  511.   
  512.         //dst_pix_fmt = PIX_FMT_YUV420P;  
  513.         /* point pict at the queue */  
  514.   
  515.         pict.data[0] = vp->bmp->pixels[0];  
  516.         pict.data[1] = vp->bmp->pixels[2];  
  517.         pict.data[2] = vp->bmp->pixels[1];  
  518.   
  519.         pict.linesize[0] = vp->bmp->pitches[0];  
  520.         pict.linesize[1] = vp->bmp->pitches[2];  
  521.         pict.linesize[2] = vp->bmp->pitches[1];  
  522.   
  523.         // Convert the image into YUV format that SDL uses  
  524.         /*img_convert(&pict, dst_pix_fmt, 
  525.                     (AVPicture *)pFrame, is->video_st->codec->pix_fmt, 
  526.                     is->video_st->codec->width, is->video_st->codec->height);*/  
  527.         sws_scale(img_convert_ctx, pFrame->data, pFrame->linesize,  
  528.                           0, is->video_st->codec->height, pict.data, pict.linesize);  
  529.         SDL_UnlockYUVOverlay(vp->bmp);  
  530.         vp->pts = pts;  
  531.   
  532.         /* now we inform our display thread that we have a pic ready */  
  533.         if(++is->pictq_windex == VIDEO_PICTURE_QUEUE_SIZE)  
  534.         {  
  535.             is->pictq_windex = 0;  
  536.         }  
  537.         SDL_LockMutex(is->pictq_mutex);  
  538.         is->pictq_size++;  
  539.         SDL_UnlockMutex(is->pictq_mutex);  
  540.     }  
  541.     return 0;  
  542. }  
  543.   
  544. double synchronize_video(VideoState *is, AVFrame *src_frame, double pts)  
  545. {  
  546.     double frame_delay;  
  547.   
  548.     if(pts != 0)  
  549.     {  
  550.         /* if we have pts, set video clock to it */  
  551.         is->video_clock = pts;  
  552.     }  
  553.     else  
  554.     {  
  555.         /* if we aren‘t given a pts, set it to the clock */  
  556.         pts = is->video_clock;  
  557.     }  
  558.     /* update the video clock */  
  559.     frame_delay = av_q2d(is->video_st->codec->time_base);  
  560.     /* if we are repeating a frame, adjust clock accordingly */  
  561.     frame_delay += src_frame->repeat_pict * (frame_delay * 0.5);  
  562.     is->video_clock += frame_delay;  
  563.     return pts;  
  564. }  
  565. uint64_t global_video_pkt_pts = AV_NOPTS_VALUE;  
  566.   
  567. /* These are called whenever we allocate a frame 
  568. * buffer. We use this to store the global_pts in 
  569. * a frame at the time it is allocated. 
  570. */  
  571. int our_get_buffer(struct AVCodecContext *c, AVFrame *pic)  
  572. {  
  573.     int ret = avcodec_default_get_buffer(c, pic);  
  574.     uint64_t *pts = (uint64_t *)av_malloc(sizeof(uint64_t));  
  575.     *pts = global_video_pkt_pts;  
  576.     pic->opaque = pts;  
  577.     return ret;  
  578. }  
  579. void our_release_buffer(struct AVCodecContext *c, AVFrame *pic)  
  580. {  
  581.     if(pic) av_freep(&pic->opaque);  
  582.     avcodec_default_release_buffer(c, pic);  
  583. }  
  584.   
  585. int video_thread(void *arg)  
  586. {  
  587.     VideoState *is = (VideoState *)arg;  
  588.     AVPacket pkt1, *packet = &pkt1;  
  589.     int len1, frameFinished;  
  590.     AVFrame *pFrame;  
  591.     double pts;  
  592.   
  593.     pFrame = avcodec_alloc_frame();  
  594.   
  595.     for(;;)  
  596.     {  
  597.         if(packet_queue_get(&is->videoq, packet, 1) < 0)  
  598.         {  
  599.             // means we quit getting packets  
  600.             break;  
  601.         }  
  602.         pts = 0;  
  603.   
  604.         // Save global pts to be stored in pFrame in first call  
  605.         global_video_pkt_pts = packet->pts;  
  606.         // Decode video frame  
  607.         len1 = avcodec_decode_video(is->video_st->codec, pFrame, &frameFinished,  
  608.                                     packet->data, packet->size);  
  609.         if(packet->dts == AV_NOPTS_VALUE  
  610.                 && pFrame->opaque && *(uint64_t*)pFrame->opaque != AV_NOPTS_VALUE)  
  611.         {  
  612.             pts = *(uint64_t *)pFrame->opaque;  
  613.         }  
  614.         else if(packet->dts != AV_NOPTS_VALUE)  
  615.         {  
  616.             pts = packet->dts;  
  617.         }  
  618.         else  
  619.         {  
  620.             pts = 0;  
  621.         }  
  622.         pts *= av_q2d(is->video_st->time_base);  
  623.   
  624.         // Did we get a video frame?  
  625.         if(frameFinished)  
  626.         {  
  627.             pts = synchronize_video(is, pFrame, pts);  
  628.             if(queue_picture(is, pFrame, pts) < 0)  
  629.             {  
  630.                 break;  
  631.             }  
  632.         }  
  633.         av_free_packet(packet);  
  634.     }  
  635.     av_free(pFrame);  
  636.     return 0;  
  637. }  
  638.   
  639. int stream_component_open(VideoState *is, int stream_index)  
  640. {  
  641.     AVFormatContext *pFormatCtx = is->pFormatCtx;  
  642.     AVCodecContext *codecCtx;  
  643.     AVCodec *codec;  
  644.     SDL_AudioSpec wanted_spec, spec;  
  645.   
  646.     if(stream_index < 0 || stream_index >= pFormatCtx->nb_streams)  
  647.     {  
  648.         return -1;  
  649.     }  
  650.   
  651.     // Get a pointer to the codec context for the video stream  
  652.     codecCtx = pFormatCtx->streams[stream_index]->codec;  
  653.   
  654.     if(codecCtx->codec_type == CODEC_TYPE_AUDIO)  
  655.     {  
  656.         // Set audio settings from codec info  
  657.         wanted_spec.freq = codecCtx->sample_rate;  
  658.         wanted_spec.format = AUDIO_S16SYS;  
  659.         wanted_spec.channels = codecCtx->channels;  
  660.         wanted_spec.silence = 0;  
  661.         wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;  
  662.         wanted_spec.callback = audio_callback;  
  663.         wanted_spec.userdata = is;  
  664.   
  665.         if(SDL_OpenAudio(&wanted_spec, &spec) < 0)  
  666.         {  
  667.             fprintf(stderr, "SDL_OpenAudio: %s/n", SDL_GetError());  
  668.             return -1;  
  669.         }  
  670.         is->audio_hw_buf_size = spec.size;  
  671.     }  
  672.     codec = avcodec_find_decoder(codecCtx->codec_id);  
  673.   
  674.     if(!codec || (avcodec_open(codecCtx, codec) < 0))  
  675.     {  
  676.         fprintf(stderr, "Unsupported codec!/n");  
  677.         return -1;  
  678.     }  
  679.   
  680.     switch(codecCtx->codec_type)  
  681.     {  
  682.     case CODEC_TYPE_AUDIO:  
  683.         is->audioStream = stream_index;  
  684.         is->audio_st = pFormatCtx->streams[stream_index];  
  685.         is->audio_buf_size = 0;  
  686.         is->audio_buf_index = 0;  
  687.         memset(&is->audio_pkt, 0, sizeof(is->audio_pkt));  
  688.         packet_queue_init(&is->audioq);  
  689.         SDL_PauseAudio(0);  
  690.         break;  
  691.     case CODEC_TYPE_VIDEO:  
  692.         is->videoStream = stream_index;  
  693.         is->video_st = pFormatCtx->streams[stream_index];  
  694.   
  695.         is->frame_timer = (double)av_gettime() / 1000000.0;  
  696.         is->frame_last_delay = 40e-3;  
  697.   
  698.         packet_queue_init(&is->videoq);  
  699.         is->video_tid = SDL_CreateThread(video_thread, is);  
  700.         codecCtx->get_buffer = our_get_buffer;  
  701.         codecCtx->release_buffer = our_release_buffer;  
  702.         break;  
  703.     default:  
  704.         break;  
  705.     }  
  706.     return 0;  
  707. }  
  708.   
  709. int decode_interrupt_cb(void)  
  710. {  
  711.     return (global_video_state && global_video_state->quit);  
  712. }  
  713.   
  714. int decode_thread(void *arg)  
  715. {  
  716.   
  717.     VideoState *is = (VideoState *)arg;  
  718.     AVFormatContext *pFormatCtx;  
  719.     AVPacket pkt1, *packet = &pkt1;  
  720.   
  721.     int video_index = -1;  
  722.     int audio_index = -1;  
  723.     int i;  
  724.   
  725.     is->videoStream=-1;  
  726.     is->audioStream=-1;  
  727.   
  728.     global_video_state = is;  
  729.     // will interrupt blocking functions if we quit!  
  730.     url_set_interrupt_cb(decode_interrupt_cb);  
  731.   
  732.     // Open video file  
  733.     if(av_open_input_file(&pFormatCtx, is->filename, NULL, 0, NULL)!=0)  
  734.         return -1; // Couldn‘t open file  
  735.   
  736.     is->pFormatCtx = pFormatCtx;  
  737.   
  738.     // Retrieve stream information  
  739.     if(av_find_stream_info(pFormatCtx)<0)  
  740.         return -1; // Couldn‘t find stream information  
  741.   
  742.     // Dump information about file onto standard error  
  743.     dump_format(pFormatCtx, 0, is->filename, 0);  
  744.   
  745.     // Find the first video stream  
  746.   
  747.     for(i=0; i<pFormatCtx->nb_streams; i++)  
  748.     {  
  749.         if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO &&  
  750.                 video_index < 0)  
  751.         {  
  752.             video_index=i;  
  753.         }  
  754.         if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_AUDIO &&  
  755.                 audio_index < 0)  
  756.         {  
  757.             audio_index=i;  
  758.         }  
  759.     }  
  760.     if(audio_index >= 0)  
  761.     {  
  762.         stream_component_open(is, audio_index);  
  763.     }  
  764.     if(video_index >= 0)  
  765.     {  
  766.         stream_component_open(is, video_index);  
  767.     }  
  768.   
  769.     if(is->videoStream < 0 || is->audioStream < 0)  
  770.     {  
  771.         fprintf(stderr, "%s: could not open codecs/n", is->filename);  
  772.         goto fail;  
  773.     }  
  774.   
  775.     // main decode loop  
  776.   
  777.     for(;;)  
  778.     {  
  779.         if(is->quit)  
  780.         {  
  781.             break;  
  782.         }  
  783.         // seek stuff goes here  
  784.         if(is->audioq.size > MAX_AUDIOQ_SIZE ||  
  785.                 is->videoq.size > MAX_VIDEOQ_SIZE)  
  786.         {  
  787.             SDL_Delay(10);  
  788.             continue;  
  789.         }  
  790.         if(av_read_frame(is->pFormatCtx, packet) < 0)  
  791.         {  
  792.             if(url_ferror(pFormatCtx->pb) == 0)  
  793.             {  
  794.                 SDL_Delay(100); /* no error; wait for user input */  
  795.                 continue;  
  796.             }  
  797.             else  
  798.             {  
  799.                 break;  
  800.             }  
  801.         }  
  802.         // Is this a packet from the video stream?  
  803.         if(packet->stream_index == is->videoStream)  
  804.         {  
  805.             packet_queue_put(&is->videoq, packet);  
  806.         }  
  807.         else if(packet->stream_index == is->audioStream)  
  808.         {  
  809.             packet_queue_put(&is->audioq, packet);  
  810.         }  
  811.         else  
  812.         {  
  813.             av_free_packet(packet);  
  814.         }  
  815.     }  
  816.     /* all done - wait for it */  
  817.     while(!is->quit)  
  818.     {  
  819.         SDL_Delay(100);  
  820.     }  
  821.   
  822. fail:  
  823.     {  
  824.         SDL_Event event;  
  825.         event.type = FF_QUIT_EVENT;  
  826.         event.user.data1 = is;  
  827.         SDL_PushEvent(&event);  
  828.     }  
  829.     return 0;  
  830. }  
  831.   
  832. int main(int argc, char *argv[])  
  833. {  
  834.   
  835.     SDL_Event       event;  
  836.     VideoState      *is;  
  837.     is = (VideoState *)av_mallocz(sizeof(VideoState));  
  838.     if(argc < 2)  
  839.     {  
  840.         fprintf(stderr, "Usage: test <file>/n");  
  841.         exit(1);  
  842.     }  
  843.     // Register all formats and codecs  
  844.     av_register_all();  
  845.     if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER))  
  846.     {  
  847.         fprintf(stderr, "Could not initialize SDL - %s/n", SDL_GetError());  
  848.         exit(1);  
  849.     }  
  850.   
  851.     // Make a screen to put our video  
  852. #ifndef __DARWIN__  
  853.     screen = SDL_SetVideoMode(640, 480, 0, 0);  
  854. #else  
  855.     screen = SDL_SetVideoMode(640, 480, 24, 0);  
  856. #endif  
  857.     if(!screen)  
  858.     {  
  859.         fprintf(stderr, "SDL: could not set video mode - exiting/n");  
  860.         exit(1);  
  861.     }  
  862.   
  863.     //pstrcpy(is->filename, sizeof(is->filename), argv[1]);  
  864.     strcpy(is->filename,argv[1]);  
  865.     is->pictq_mutex = SDL_CreateMutex();  
  866.     is->pictq_cond = SDL_CreateCond();  
  867.   
  868.     schedule_refresh(is, 40);  
  869.   
  870.     is->parse_tid = SDL_CreateThread(decode_thread, is);  
  871.     if(!is->parse_tid)  
  872.     {  
  873.         av_free(is);  
  874.         return -1;  
  875.     }  
  876.     for(;;)  
  877.     {  
  878.         SDL_WaitEvent(&event);  
  879.         switch(event.type)  
  880.         {  
  881.         case FF_QUIT_EVENT:  
  882.         case SDL_QUIT:  
  883.             is->quit = 1;  
  884.             SDL_Quit();  
  885.             exit(0);  
  886.             break;  
  887.         case FF_ALLOC_EVENT:  
  888.             alloc_picture(event.user.data1);  
  889.             break;  
  890.         case FF_REFRESH_EVENT:  
  891.             video_refresh_timer(event.user.data1);  
  892.             break;  
  893.         default:  
  894.             break;  
  895.         }  
  896.     }  
  897.     return 0;  

ffmpeg+sdl教程----编写一个简单的播放器5(同步视频到音频)