Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2117260
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2015-08-25 17:09:12

更新版:基于ffmpeg-2.7.2

1. 流程

  1. main中创建线程decode_thread,作用是从视频文件中分离出vidoe与sound帧
  2. decode_thread
  3. {
  4.     stream_component_open(is, audio_index); --> audio_callback
  5.     stream_component_open(is, video_index); --> video_thread
  6.     while(1)
  7.     {
  8.         av_read_frame();
  9.         将video的数据 put_queue
  10.         将sound的数据 put_queue
  11.     }
  12. }

  13. audio_callback
  14. {
  15.     audio的流程不变
  16. }

  17. video_thread
  18. {
  19.     a.从video的帧队列中packet_queue_get
  20.     b. decode_video2解码
  21.     c. queue_picture显示
  22. }
  23. queue_picture
  24. {
  25. a. 等侍信号pictq_cond
  26. b. 如果是第1次需要初始化SDL_screeen
  27. c. 转换图片格式sws_scale
  28. }

  29. video_refresh_timer
  30. {
  31. a. SDL_DisplayYUVOverlay显示图像
  32. b. 显示完成后发送信号pictq_cond
  33. }
2.代码
  1. cong@msi:/work/ffmpeg/test/4spawn$ cat spawn.c
  2. #include "utils.h"
  3. #include <libavcodec/avcodec.h>
  4. #include <libavformat/avformat.h>
  5. #include <libswscale/swscale.h>
  6. #include <libswresample/swresample.h>
  7. #include <libavutil/avstring.h>
  8. #include <libavutil/pixfmt.h>
  9. #include <libavutil/log.h>
  10. #include <SDL/SDL.h>
  11. #include <SDL/SDL_thread.h>
  12. #include <stdio.h>
  13. #include <math.h>

  14. #define SDL_AUDIO_BUFFER_SIZE 4096
  15. #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000

  16. #define MAX_AUDIOQ_SIZE (5 * 16 * 1024)
  17. #define MAX_VIDEOQ_SIZE (5 * 256 * 1024)


  18. #define FF_REFRESH_EVENT (SDL_USEREVENT)
  19. #define FF_QUIT_EVENT (SDL_USEREVENT + 1)

  20. typedef struct PacketQueue
  21. {
  22.     AVPacketList * first_pkt, *last_pkt;
  23.     int nb_packets;
  24.     int size;
  25.     SDL_mutex *mutex;
  26.     SDL_cond * cond;
  27. }PacketQueue;

  28. static int signal_quit = 0;
  29. SDL_mutex *affmutex;
  30. SDL_Event sdlevent;

  31. #define VIDEO_PICTURE_QUEUE_SIZE 1

  32. typedef struct VideoState {
  33.     int videoindex;
  34.     int sndindex;
  35.     int frameFinished;
  36.     int wanted_freq;
  37.     int wanted_samples;
  38.     int wanted_channels;
  39.     char filename[1024];
  40.     int pictq_size, pictq_rindex, pictq_windex;
  41.     SDL_Thread* video_tid;
  42.     AVFormatContext* pFormatCtx;
  43.     AVCodecContext* vdoCodecCtx;
  44.     AVCodecContext* sndCodecCtx;
  45.     AVCodec* vdoCodec;
  46.     AVCodec* sndCodec;
  47.     AVFrame* pFrameYUV;
  48.     AVPacket* packet;
  49.     struct SwsContext *img_convert_ctx;
  50.     struct SwrContext *swr_ctx;
  51.     SDL_mutex *pictq_mutex;
  52.     SDL_cond *pictq_cond;
  53.     SDL_Surface* psscreen;
  54.     SDL_Overlay* overlay;
  55.     SDL_Rect rect;
  56.     SDL_mutex *screen_mutex;
  57.     enum AVSampleFormat wanted_fmt;
  58.     int64_t wanted_channel_layout;
  59.     PacketQueue audioq;
  60.     PacketQueue videoq;
  61.     DECLARE_ALIGNED(16,uint8_t,audio_buf2) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
  62. }VideoState;

  63. void video_refresh_timer(void* arg);

  64. static int sdl_event_thread(void* data)
  65. {
  66.     while((0==signal_quit))
  67.     {
  68.         SDL_LockMutex(affmutex);
  69.         while(SDL_PollEvent(&sdlevent))
  70.         {
  71.             switch(sdlevent.type)
  72.             {
  73.                 case FF_QUIT_EVENT:
  74.                 case SDL_QUIT:
  75.                     {
  76.                         dbmsg("next change signal_quit to 1");
  77.                         signal_quit = 1;
  78.                         SDL_Quit();
  79.                     }
  80.                     break;
  81.                 case FF_REFRESH_EVENT:
  82.                   video_refresh_timer(sdlevent.user.data1);
  83.                   break;
  84.                 default:
  85.                     break;
  86.             }
  87.         }
  88.         SDL_UnlockMutex(affmutex);
  89.     }
  90. }

  91. void packet_queue_init(PacketQueue *q)
  92. {
  93.     memset(q, 0, sizeof(PacketQueue));
  94.     q->mutex = SDL_CreateMutex();
  95.     q->cond = SDL_CreateCond();
  96. }

  97. int packet_queue_put(PacketQueue *q, AVPacket *pkt)
  98. {
  99.     AVPacketList *pkt1;
  100.     if(av_dup_packet(pkt) < 0)
  101.         return -1;
  102.     pkt1 = av_malloc(sizeof(AVPacketList));
  103.     if (!pkt1)
  104.         return -1;
  105.     pkt1->pkt = *pkt;
  106.     pkt1->next = NULL;

  107.     SDL_LockMutex(q->mutex);
  108.     if (!q->last_pkt)
  109.         q->first_pkt = pkt1;
  110.     else
  111.         q->last_pkt->next = pkt1;
  112.     q->last_pkt = pkt1;
  113.     q->nb_packets++;
  114.     q->size += pkt1->pkt.size;
  115.     //dbmsg("put_queue and send singal");
  116.     SDL_CondSignal(q->cond);
  117.     SDL_UnlockMutex(q->mutex);
  118.     return 0;
  119. }

  120. static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
  121. {
  122.     AVPacketList *pkt1;
  123.     int ret;
  124.     SDL_LockMutex(q->mutex);
  125.     for(;;)
  126.     {
  127.         pkt1 = q->first_pkt;
  128.         if (pkt1)
  129.         {
  130.             q->first_pkt = pkt1->next;
  131.             if (!q->first_pkt)
  132.                 q->last_pkt = NULL;
  133.             q->nb_packets--;
  134.             q->size -= pkt1->pkt.size;
  135.             *pkt = pkt1->pkt;
  136.             av_free(pkt1);
  137.             ret = 1;
  138.             break;
  139.         } else if (!block) {
  140.             ret = 0;
  141.             break;
  142.         } else {
  143.             SDL_CondWait(q->cond, q->mutex);
  144.             dbmsg("get_queue and get singal");
  145.         }
  146.     }
  147.     SDL_UnlockMutex(q->mutex);
  148.     return ret;
  149. }

  150. int audio_decode_frame(VideoState* is)
  151. {
  152.     int i;
  153.     int len1,len2, data_size, got_frame;
  154.     int new_packet;
  155.     int64_t dec_channel_layout;
  156.     uint8_t *out[] = { is->audio_buf2 };
  157.     AVPacket *pkt = av_mallocz(sizeof(AVPacket));
  158.     AVPacket *pkt_temp = av_mallocz(sizeof(AVPacket));
  159.     AVFrame *frame = av_frame_alloc();
  160.     for(;;)
  161.     {
  162.         while(pkt_temp->size>0 || (!pkt_temp->data && new_packet))
  163.         {
  164.             if(frame)
  165.             {
  166.                 //dbmsg("av_get default frame");
  167.                 av_frame_unref(frame); //reset frame
  168.             }
  169.             new_packet = 0;
  170.             len1 = avcodec_decode_audio4(is->sndCodecCtx, frame, &got_frame, pkt_temp); //decode data is store in frame
  171.             if(len1 < 0)
  172.             {
  173.                 pkt_temp->size = 0;
  174.                 break;
  175.             }
  176.             //dbmsg("len1=%d, linesize=%d",len1, frame->linesize[0]);

  177.             pkt_temp->data += len1;
  178.             pkt_temp->size -= len1;

  179.             if(got_frame <= 0) /* No data yet, get more frames */
  180.                 continue;
  181.             data_size = av_samples_get_buffer_size(NULL, is->sndCodecCtx->channels, frame->nb_samples, is->sndCodecCtx->sample_fmt, 1);
  182.             dec_channel_layout = (frame->channel_layout && frame->channels==av_get_channel_layout_nb_channels(frame->channel_layout))?
  183.                 frame->channel_layout: is->wanted_channel_layout;
  184. #if 0
  185.             dbmsg("format=%d:%d,layout=%lld:%lld,rate=%d:%d,samples=%d:%d",frame->format,is->wanted_fmt,
  186.                    (long long) dec_channel_layout,(long long)av_get_default_channel_layout(is->wanted_channels),
  187.               frame->sample_rate,is->wanted_freq,frame->nb_samples,is->wanted_samples );

  188.             dbmsg("wanted_channel_layout=%lld", (long long)is->wanted_channel_layout);
  189.             dbmsg("wanted_fmt=%d", is->wanted_fmt);
  190.             dbmsg("spec.freq=%d", is->wanted_freq);
  191. #endif
  192.             //check: format,channel_layout,rate,sample
  193.             if((NULL==is->swr_ctx) && ( (frame->format!=is->wanted_fmt) || (dec_channel_layout!=av_get_default_channel_layout(is->wanted_channels)) ||
  194.               (frame->sample_rate!=is->wanted_freq) || (frame->nb_samples!=is->wanted_samples)) )
  195.             {
  196.                 if(is->swr_ctx != NULL)
  197.                     swr_free(&is->swr_ctx);
  198. #if 0
  199.                 dbmsg("wanted_channel_layout=%lld, wanted_fmt=%d, wanted_sample=%d, dec_channel_layout=%lld, frame->format=%d, frame->sample_rate=%d",
  200.                 (long long)is->wanted_channel_layout, is->wanted_fmt, is->wanted_samples, (long long)dec_channel_layout, frame->format, frame->sample_rate);
  201. #endif
  202.                 is->swr_ctx = swr_alloc_set_opts(NULL, is->wanted_channel_layout, is->wanted_fmt, is->wanted_freq, dec_channel_layout, frame->format, frame->sample_rate, 0, NULL);
  203.                 if(is->swr_ctx == NULL)
  204.                 {
  205.                     dbmsg("swr_ctx == NULL");
  206.                 }
  207.                 swr_init(is->swr_ctx);
  208.             }
  209.             if(is->swr_ctx)
  210.             {
  211.                 len2 = swr_convert(is->swr_ctx, out, sizeof(is->audio_buf2)/is->wanted_channels/av_get_bytes_per_sample(frame->format),(const uint8_t **)frame->extended_data, frame->nb_samples);
  212.                 data_size = len2 * is->wanted_channels * av_get_bytes_per_sample(is->wanted_fmt);
  213.             }else {
  214.                 memcpy(is->audio_buf2, frame->data[0], frame->linesize[0]);
  215.             }

  216.             return data_size;
  217.         }
  218.         if(pkt->data)
  219.             av_free_packet(pkt);
  220.         memset(pkt_temp, 0, sizeof(*pkt_temp));
  221.         if(signal_quit)
  222.             return -1;
  223.         if((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
  224.         {
  225.             dbmsg("get packet=%d", new_packet);
  226.             return -1;
  227.         }

  228.         *pkt_temp = *pkt;
  229.     }
  230. }

  231. void audio_callback(void *userdata, Uint8 *stream, int len)
  232. {
  233.     int i;
  234.     VideoState* is = (VideoState*)userdata;
  235.     int len1, audio_size;

  236.     static unsigned int audio_buf_size = 0;
  237.     static unsigned int audio_buf_index = 0;

  238.     while(len > 0)
  239.     {
  240.         if(audio_buf_index >= audio_buf_size)
  241.         {
  242.             audio_size = audio_decode_frame(is); //decode data is store in is->audio_buf2
  243.             //dbmsg("audio_size=%d", audio_size);
  244.             if(audio_size < 0)
  245.             {
  246.                 /* If error, output silence */
  247.                 audio_buf_size = 1024;
  248.                 memset(is->audio_buf2, 0, audio_buf_size);
  249.             } else {
  250.                 audio_buf_size = audio_size;
  251.             }
  252.             audio_buf_index = 0;
  253.         }
  254.         //dbmsg("len=%d, audio_buf_size=%d, audio_buf_index=%d", len, audio_buf_size, audio_buf_index);
  255.         len1 = audio_buf_size - audio_buf_index;
  256.         //dbmsg("len1=%d", len1);
  257.         if(len1 > len)
  258.             len1 = len;
  259.         //dbmsg("len1 = %d", len1);
  260.         memcpy(stream, (uint8_t *)is->audio_buf2 + audio_buf_index, len1);
  261.         len -= len1;
  262.         stream += len1;
  263.         audio_buf_index += len1;
  264.     }
  265. }

  266. static Uint32 sdl_refresh_timer_cb(Uint32 interval, void *opaque) {
  267.   SDL_Event event;
  268.   event.type = FF_REFRESH_EVENT;
  269.   event.user.data1 = opaque;
  270.   SDL_PushEvent(&event);
  271.   return 0; /* 0 means stop timer */
  272. }

  273. /* schedule a video refresh in 'delay' ms */
  274. static void schedule_refresh(VideoState *is, int delay) {
  275.   SDL_AddTimer(delay, sdl_refresh_timer_cb, is);
  276. }

  277. void video_display(VideoState *is) {
  278.     SDL_LockMutex(is->screen_mutex);
  279.     SDL_DisplayYUVOverlay(is->overlay, &is->rect);
  280.     SDL_UnlockMutex(is->screen_mutex);
  281. }

  282. void video_refresh_timer(void *data)
  283. {
  284.     VideoState *is = (VideoState *)data;
  285.     if(is->pictq_size == 0) {
  286.         schedule_refresh(is, 1);
  287.     } else {
  288.         schedule_refresh(is, 40);
  289.         video_display(is);

  290.         SDL_LockMutex(is->pictq_mutex);
  291.         is->pictq_size--;
  292.         SDL_CondSignal(is->pictq_cond);
  293.         SDL_UnlockMutex(is->pictq_mutex);
  294.     }
  295. }

  296. int queue_picture(VideoState *is, AVFrame *pFrame)
  297. {
  298.     /* wait until we have space for a new pic */
  299.     SDL_LockMutex(is->pictq_mutex);
  300.     while(is->pictq_size >= VIDEO_PICTURE_QUEUE_SIZE && (0==signal_quit)) {
  301.         SDL_CondWait(is->pictq_cond, is->pictq_mutex);
  302.     }
  303.     SDL_UnlockMutex(is->pictq_mutex);

  304.     if(signal_quit)
  305.       return -1;

  306.     /* We have a place to put our picture on the queue */
  307.     SDL_LockYUVOverlay(is->overlay);
  308.     is->pFrameYUV->data[0] = is->overlay->pixels[0];
  309.     is->pFrameYUV->data[1] = is->overlay->pixels[2];
  310.     is->pFrameYUV->data[2] = is->overlay->pixels[1];
  311.     is->pFrameYUV->linesize[0] = is->overlay->pitches[0];
  312.     is->pFrameYUV->linesize[1] = is->overlay->pitches[2];
  313.     is->pFrameYUV->linesize[2] = is->overlay->pitches[1];
  314.     sws_scale(is->img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0,
  315.     is->vdoCodecCtx->height, is->pFrameYUV->data, is->pFrameYUV->linesize);
  316.     SDL_UnlockYUVOverlay(is->overlay);
  317.     SDL_LockMutex(is->pictq_mutex);
  318.     is->pictq_size++;
  319.     SDL_UnlockMutex(is->pictq_mutex);
  320.     return 0;
  321. }

  322. static int video_thread(void* data)
  323. {
  324.     VideoState *is = (VideoState *)data;
  325.     AVPacket pkt1, *packet = &pkt1;
  326.     int frameFinished;
  327.     AVFrame *pFrame;
  328.     int ret;
  329.     pFrame = av_frame_alloc();

  330.    for(;;)
  331.    {
  332.       if(signal_quit)
  333.           break;
  334.       if(packet_queue_get(&is->videoq, packet, 1) < 0) {
  335.           // means we quit getting packets
  336.           dbmsg("packet_queue_get < 0");
  337.           break;
  338.         }
  339.         // Decode video frame
  340.         if((ret=avcodec_decode_video2(is->vdoCodecCtx, pFrame, &is->frameFinished, packet)) < 0)
  341.         {
  342.             dbmsg("decocode video error");
  343.             continue;
  344.         }
  345.         if(is->frameFinished) {
  346.           if(queue_picture(is, pFrame) < 0) {
  347.             break;
  348.           }
  349.         }
  350.         av_free_packet(packet);
  351.     }
  352.     av_frame_free(&pFrame);
  353.     return 0;
  354. }

  355. static int decode_thread(void* data)
  356. {
  357.     VideoState* is = (VideoState*)data;
  358.     is->packet = (AVPacket*)av_malloc(sizeof(AVPacket));
  359.     while( (av_read_frame(is->pFormatCtx, is->packet)>=0) && (signal_quit==0))
  360.     {
  361.         if(is->packet->stream_index == is->videoindex)
  362.         {
  363.             packet_queue_put(&is->videoq, is->packet);
  364.         }

  365.         if(is->packet->stream_index == is->sndindex)
  366.         {
  367.             packet_queue_put(&is->audioq, is->packet);
  368.         }
  369.     }
  370.     return 0;
  371. }

  372. int init_ffmpeg_and_SDL(VideoState* is, char* video_file)
  373. {
  374.     int i=0;
  375.     int ret;
  376.     SDL_AudioSpec wanted_spec, real_spec;
  377.     is->videoindex = -1;
  378.     is->sndindex = -1;
  379.     if(NULL == video_file)
  380.     {
  381.         dbmsg("input file is NULL");
  382.         return -1;
  383.     }
  384.     SDL_Init(SDL_INIT_EVERYTHING);
  385.     avcodec_register_all();
  386.     avfilter_register_all();
  387.     av_register_all();

  388.     is->pFormatCtx = avformat_alloc_context();

  389.     if(avformat_open_input(&is->pFormatCtx, video_file, NULL, NULL)!=0)
  390.         return -1;

  391.     if(avformat_find_stream_info(is->pFormatCtx, NULL)<0)
  392.         return -1;
  393.     av_dump_format(is->pFormatCtx,0, 0, 0);

  394.     for(i=0; i<is->pFormatCtx->nb_streams; i++)
  395.     {
  396.         if(is->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  397.         {
  398.             is->videoindex= i;
  399.         }
  400.         if(is->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
  401.         {
  402.             is->sndindex= i;
  403.         }
  404.     }
  405.     if(is->videoindex== -1)
  406.         dbmsg("no video stream found!");
  407.     if(is->sndindex== -1)
  408.         dbmsg("no sound stream found!");
  409.     dbmsg("videoindex=%d, sndindex=%d", is->videoindex, is->sndindex);

  410.     if(is->videoindex != -1)
  411.     {
  412.         is->vdoCodecCtx = is->pFormatCtx->streams[is->videoindex]->codec;
  413.         is->vdoCodec = avcodec_find_decoder(is->vdoCodecCtx->codec_id);
  414.         if(is->vdoCodec == NULL)
  415.         {
  416.             dbmsg("Codec not found");
  417.             return -1;
  418.         }
  419.         if(avcodec_open2(is->vdoCodecCtx, is->vdoCodec, NULL) < 0)
  420.             return -1;
  421.         is->pFrameYUV = av_frame_alloc();
  422.         is->img_convert_ctx = sws_getContext(is->vdoCodecCtx->width, is->vdoCodecCtx->height, is->vdoCodecCtx->pix_fmt,
  423.               is->vdoCodecCtx->width, is->vdoCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
  424.         if(is->img_convert_ctx == NULL)
  425.         {
  426.             dbmsg("img_convert error");
  427.             return -1;
  428.         }
  429.         is->psscreen = SDL_SetVideoMode(is->vdoCodecCtx->width, is->vdoCodecCtx->height, 0, SDL_SWSURFACE);
  430.         SDL_WM_SetCaption( "FFMPEG Window", NULL);
  431.         is->overlay = SDL_CreateYUVOverlay(is->vdoCodecCtx->width, is->vdoCodecCtx->height, SDL_YV12_OVERLAY, is->psscreen);
  432.         is->rect.x = 0;
  433.         is->rect.y = 0;
  434.      is->rect.w = is->vdoCodecCtx->width;
  435.         is->rect.h = is->vdoCodecCtx->height;
  436.         packet_queue_init(&is->videoq);
  437.         is->video_tid = SDL_CreateThread(video_thread, is);
  438.     }
  439.     if(is->sndindex != -1)
  440.     {
  441.         is->sndCodecCtx = is->pFormatCtx->streams[is->sndindex]->codec;
  442.         is->sndCodec = avcodec_find_decoder(is->sndCodecCtx->codec_id);
  443.         if(is->sndCodec == NULL)
  444.         {
  445.             dbmsg("Codec not found");
  446.             return -1;
  447.         }
  448.         if(avcodec_open2(is->sndCodecCtx, is->sndCodec, NULL) < 0)
  449.             return -1;

  450.         wanted_spec.freq = is->sndCodecCtx->sample_rate;
  451.         wanted_spec.format = AUDIO_S16SYS;
  452.         wanted_spec.channels = is->sndCodecCtx->channels;
  453.         wanted_spec.silence = 0;
  454.         wanted_spec.samples = 2048;
  455.         wanted_spec.callback = audio_callback;
  456.         wanted_spec.userdata = is;
  457.         if(SDL_OpenAudio(&wanted_spec, &real_spec) < 0)
  458.         {
  459.             dbmsg("SDL_OpenAudio:%s", SDL_GetError());
  460.             return -1;
  461.         }
  462.         //store infomation for audio swr_convert
  463.         is->wanted_fmt = AV_SAMPLE_FMT_S16; //AUDIO_S16SYS;
  464.         is->wanted_channel_layout = av_get_default_channel_layout(is->sndCodecCtx->channels);
  465.         is->wanted_freq = real_spec.freq;
  466.         is->wanted_samples = real_spec.samples;
  467.         is->wanted_channels = real_spec.channels;
  468.         //dbmsg("freq=%d, channels=%d, samples=%d", is->wanted_freq, is->wanted_channels, is->wanted_samples);
  469.         packet_queue_init(&is->audioq);
  470.         SDL_PauseAudio(0);
  471.     }
  472.     return 0;
  473. }

  474. int main(int argc, char **argv)
  475. {
  476.     int ret;
  477.     SDL_Thread* sdl_thread;
  478.     SDL_Thread* decode_thread_id;
  479.     VideoState* is = (VideoState*) av_mallocz(sizeof(VideoState));

  480.     if( (ret=init_ffmpeg_and_SDL(is, argv[1])) != 0)
  481.     {
  482.         dbmsg("init_ffmpeg_and SDL error");
  483.         return -1;
  484.     }

  485.     is->pictq_mutex = SDL_CreateMutex();
  486.     is->pictq_cond = SDL_CreateCond();

  487.     //sdl get signal quit
  488.     affmutex = SDL_CreateMutex();
  489.     decode_thread_id = SDL_CreateThread(decode_thread, is);
  490.     sdl_thread = SDL_CreateThread(sdl_event_thread, NULL);

  491.     schedule_refresh(is, 40);

  492.     SDL_WaitThread(sdl_thread, &ret);
  493.     SDL_WaitThread(decode_thread_id, &ret);
  494.     SDL_WaitThread(is->video_tid,&ret);
  495.     SDL_DestroyMutex(affmutex);
  496.     av_free_packet(is->packet);
  497.     av_free(is->pFrameYUV);
  498.     avcodec_close(is->vdoCodecCtx);
  499.     avcodec_close(is->sndCodecCtx);
  500.     avformat_close_input(&is->pFormatCtx);
  501.     return 0;
  502. }
  503. cong@msi:/work/ffmpeg/test/4spawn$
3. 代码打包   
4spawn.rar (下载后改名为4spawn.tar.gz)






阅读(1756) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~