ffmpeg学习---4.Playing Sound

来源:互联网 发布:变频器模拟软件 编辑:程序博客网 时间:2024/06/14 07:46
一.最原始版的
http://dranger.com/ffmpeg/tutorial03.html
1. 3playsound.c
  1. cong@msi:/work/ffmpeg/test/4sound$ cat sound.
  2. #include "utils.h"
  3. #include <libavformat/avformat.h>
  4. #include <libswscale/swscale.h>
  5. #include <SDL/SDL.h>

  6. #define SDL_AUDIO_BUFFER_SIZE 4096
  7. #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
  8. SDL_mutex *affmutex;
  9. SDL_Event sdlevent;
  10. int signal_quit = 1;
  11. typedef struct PacketQueue
  12. {
  13.     AVPacketList * first_pkt, *last_pkt;
  14.     int nb_packets;
  15.     int size;
  16.     SDL_mutex *mutex;
  17.     SDL_cond * cond;
  18. }PacketQueue;
  19. PacketQueue audioq;

  20. static int eventThread(void* data)
  21. {
  22.     while(signal_quit)
  23.     {
  24.         SDL_LockMutex(affmutex);
  25.         while(SDL_PollEvent(&sdlevent))
  26.         {
  27.             switch(sdlevent.type)
  28.             {
  29.                 case SDL_QUIT:
  30.                     {
  31.                         signal_quit = 0;
  32.                     }
  33.                     break;
  34.                 default:
  35.                     break;

  36.             }
  37.         }
  38.         SDL_UnlockMutex(affmutex);
  39.     } 
  40. }
  41. void packet_queue_init(PacketQueue *q)
  42. {
  43.     memset(q, 0, sizeof(PacketQueue));
  44.     q->mutex = SDL_CreateMutex();
  45.     q->cond = SDL_CreateCond();
  46. }

  47. int packet_queue_put(PacketQueue *q, AVPacket *pkt)
  48. {

  49.     AVPacketList *pkt1;
  50.     if(av_dup_packet(pkt) < 0)
  51.         return -1;
  52.     pkt1 = av_malloc(sizeof(AVPacketList));
  53.     if (!pkt1)
  54.         return -1;
  55.     pkt1->pkt = *pkt;
  56.     pkt1->next = NULL;

  57.     SDL_LockMutex(q->mutex);

  58.     if (!q->last_pkt)
  59.         q->first_pkt = pkt1;
  60.     else
  61.         q->last_pkt->next = pkt1;
  62.     q->last_pkt = pkt1;
  63.     q->nb_packets++;
  64.     q->size += pkt1->pkt.size;
  65.     SDL_CondSignal(q->cond);

  66.     SDL_UnlockMutex(q->mutex);
  67.     return 0;
  68. }

  69. static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
  70. {
  71.     AVPacketList *pkt1;
  72.     int ret;
  73.     SDL_LockMutex(q->mutex);
  74.     for(;;)
  75.     {
  76.         if(== signal_quit)
  77.         {
  78.             ret = -1;
  79.             break;
  80.         }
  81.         pkt1 = q->first_pkt;
  82.         if (pkt1)
  83.         {
  84.             q->first_pkt = pkt1->next;
  85.             if (!q->first_pkt)
  86.                 q->last_pkt = NULL;
  87.             q->nb_packets--;
  88.             q->size -= pkt1->pkt.size;
  89.             *pkt = pkt1->pkt;
  90.             av_free(pkt1);
  91.             ret = 1;
  92.             break;
  93.         } else if (!block) {
  94.             ret = 0;
  95.             break;
  96.         } else {
  97.             SDL_CondWait(q->cond, q->mutex);
  98.         }
  99.     }
  100.     SDL_UnlockMutex(q->mutex);
  101.     return ret;
  102. }

  103. int audio_decode_frame(AVCodecContext *aCodecCtx, AVPacket *pkt, AVPacket *pkt_temp, AVFrame *frame, uint8_t *audio_buf)
  104. {
  105.     int i;
  106.     int len1, data_size, got_frame;
  107.     int new_packet;
  108.     for(;;)
  109.     {
  110.         while(pkt_temp->size>|| (!pkt_temp->data && new_packet))
  111.         {
  112.             if(!frame)
  113.             {
  114.                 if (!(frame = av_frame_alloc())) //函数avcodec_alloc_frame不用了
  115.                     return AVERROR(ENOMEM);
  116.             }
  117.             else
  118.             {
  119.                 av_frame_unref(frame); //函数avcodec_get_frame_defaults(frame)不用了
  120.             }
  121.             new_packet = 0;
  122.             len1 = avcodec_decode_audio4(aCodecCtx, frame, &got_frame, pkt_temp); //decode data is store in frame
  123.             if(len1 < 0)
  124.             {
  125.                 pkt_temp->size = 0;
  126.                 break;
  127.             }

  128.             pkt_temp->data += len1;
  129.             pkt_temp->size -= len1;

  130.             if(got_frame <= 0) /* No data yet, get more frames */
  131.                 continue;
  132.             //dbmsg("add filter: sample=%d", frame->nb_samples)//这个地方有问题:若解码后的数据包与sdl需要的数据格式不匹配则播放产生噪声
  133.             data_size = av_samples_get_buffer_size(NULL, aCodecCtx->channels, frame->nb_samples, aCodecCtx->sample_fmt, 1);
  134.             memcpy(audio_buf, frame->data[0], frame->linesize[0]);
  135.             return data_size;
  136.         }
  137.         if(pkt->data)
  138.             av_free_packet(pkt);
  139.         memset(pkt_temp, 0, sizeof(*pkt_temp));
  140.         if(== signal_quit)
  141.             return -1;
  142.          //这个地方是本函数的开始位置,一直等侍音频数据包的到来
  143.         if((new_packet = packet_queue_get(&audioq, pkt, 1)) < 0)
  144.             return -1;
  145.         *pkt_temp = *pkt;
  146.     }
  147. }

  148. void audio_callback(void *userdata, Uint8 *stream, int len)  //这个回调函数中len=4096
  149. {
  150.     int i;
  151.     AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
  152.     int len1, audio_size;

  153.     static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
  154.     static unsigned int audio_buf_size = 0;
  155.     static unsigned int audio_buf_index = 0;

  156.     AVPacket *pkt = av_mallocz(sizeof(AVPacket));
  157.     AVPacket *pkt_temp = av_mallocz(sizeof(AVPacket));
  158.     AVFrame *frame = NULL;
  159.     //dbmsg("len=%d", len);
  160.     while(len > 0)
  161.     {
  162.         if(audio_buf_index >= audio_buf_size)
  163.         {   //如果没有音频数据包则等侍,若有数据包则解码,并将解码后的数据放在audio_buf中
  164.             audio_size = audio_decode_frame(aCodecCtx, pkt, pkt_temp, frame, audio_buf);
  165.             if(audio_size < 0)
  166.             {
  167.                 /* If error, output silence */
  168.                 audio_buf_size = 1024;
  169.                 memset(audio_buf, 0, audio_buf_size);
  170.             } else {
  171.                 audio_buf_size = audio_size;
  172.             }
  173.             audio_buf_index = 0;
  174.         }
  175.         len1 = audio_buf_size - audio_buf_index;
  176.         if(len1 > len)
  177.             len1 = len;
  178.         //将解码后的数据(audio_buf中的数据)copy到stream中进行播放
  179.         memcpy(stream, (uint8_t *)audio_buf + audio_buf_index, len1);
  180.         len -= len1;
  181.         stream += len1;
  182.         audio_buf_index += len1;
  183.     }
  184. }

  185. int main(int argc, char **argv)
  186. {
  187.     int i=0;
  188.     int ret;
  189.     int videoindex= -1;
  190.     int sndindex= -1;
  191.     int frameFinished;
  192.     AVFormatContext *pFormatCtx = NULL;
  193.     AVCodecContext * pCodecCtx;
  194.     AVCodecContext * sndCodecCtx;
  195.     AVCodec * pCodec;
  196.     AVCodec * sndCodec;
  197.     AVFrame * pFrame;
  198.     AVFrame * pFrameYUV;
  199.     AVPacket * packet; 
  200.     struct SwsContext *img_convert_ctx;

  201.     SDL_Surface* psscreen;
  202.     SDL_Overlay* overlay;
  203.     SDL_Rect rect;
  204.     SDL_Thread* sdl_thread;
  205.     SDL_AudioSpec wanted_spec, spec;
  206.     //a. ffmpeg的初始化(虽然名字是register就这么说吧)
  207.     avcodec_register_all();
  208.     avfilter_register_all();
  209.     av_register_all();
  210.     //b.打开视频文件
  211.     pFormatCtx = avformat_alloc_context();
  212.     if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
  213.         return -1; 
  214.     //c.获取视频文件的流信息,(即查看有几个视频流几个音频流)  
        if(avformat_find_stream_info(pFormatCtx, NULL)<0)
  215.         return -1;
  216.     av_dump_format(pFormatCtx,0, 0, 0);
  217.     //d.获取了视频流的index,这样以后读取一帧之后,根据索引号才能判断这一帧是不是视频帧
  218.     //同理获取了音频流的index,这样以后读取一包之后,根据索引号才能判断这一帧是不是音频帧
  219.     for(i=0; i<pFormatCtx->nb_streams; i++)
  220.     {
  221.         if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  222.         {
  223.             videoindex= i;   //获取视频流的索引
  224.         }
  225.         if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
  226.         {
  227.             sndindex= i;    //获取视频流的索引
  228.         }
  229.     }
  230.     if(videoindex== -1)
  231.     {
  232.         dbmsg("no video stream found!");
  233.         //return -1;
  234.     }
  235.     if(sndindex== -1)
  236.     {
  237.         dbmsg("no sound stream found!");
  238.         return -1;
  239.     }
  240.     //e.1为视频流寻找解码器:在c中不仅有视频流的index,还有视频流的编码codec_id,并打开解码器
  241.     if(videoindex != -1)
  242.     {
  243.         pCodecCtx = pFormatCtx->streams[videoindex]->codec;
  244.         pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
  245.         if(pCodec == NULL)
  246.         {
  247.             dbmsg("Codec not found");
  248.             return -1;
  249.         }
  250.         if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
  251.             return -1;
  252.     }
  253.     //e.2为音频流寻找解码器,并打开解码器
  254.     if(sndindex != -1)
  255.     {
  256.         sndCodecCtx = pFormatCtx->streams[sndindex]->codec;
  257.         sndCodec = avcodec_find_decoder(sndCodecCtx->codec_id);
  258.         if(sndCodec == NULL)
  259.         {
  260.             dbmsg("Codec not found");
  261.             return -1;
  262.         }

  263.         if(avcodec_open2(sndCodecCtx, sndCodec, NULL) < 0)
  264.             return -1;
  265.     }
  266.     //f.1视频显示的准备:SDL初始化,设置显示模式,创建画布
  267.     pFrame = av_frame_alloc();           //以前的avcodec_alloc_frame函数现在不用了
  268.     pFrameYUV = av_frame_alloc();        //以前的avcodec_alloc_frame函数现在不用了
  269.     SDL_Init(SDL_INIT_EVERYTHING);
  270.     psscreen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, SDL_SWSURFACE);
  271.     SDL_WM_SetCaption( "FFMPEG Window", NULL);
  272.     //注意这儿的参数SDL_YU12_OVERLAY与SDL_YUY2_OVERLAY一定要与下面sws_scale中的参数配套
  273.     overlay = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, psscreen);
  274.     //overlay = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YUY2_OVERLAY, psscreen);
  275.     
  276.     //f.2音频的准备:设置输出audio的格式
  277.     wanted_spec.freq = sndCodecCtx->sample_rate;           //采样率
  278.     wanted_spec.format = AUDIO_S16SYS;                     //SDL中的输入格式, s代表signed有符号的,16代表采样是16位的采样精度,SYS代表大小端格式按照系统默认 
  279.     wanted_spec.channels = sndCodecCtx->channels;          //声道数
  280.     wanted_spec.silence = 0;                               //需不需要静音: 0不需要,但是设为之后仍旧是有声音的,看来这个理解有误,有明白的告诉一下?????
  281.     wanted_spec.samples = 2048;                            //audio_buffer的size,通常这个值设为512到8192,ffplay设置的是1024
  282.     wanted_spec.callback = audio_callback;                 //回调函数
  283.     wanted_spec.userdata = sndCodecCtx;                    //给回调函数传的参数
  284.     if(SDL_OpenAudio(&wanted_spec, &spec) < 0)
  285.     {
  286.         dbmsg("SDL_OpenAudio:%s", SDL_GetError());
  287.         return -1;
  288.     }
  289.     packet_queue_init(&audioq);
  290.     SDL_PauseAudio(0);

  291.     //与SDL的退出相关
  292.     affmutex = SDL_CreateMutex();
  293.     sdl_thread = SDL_CreateThread(eventThread, NULL);

  294.     rect.= 0;
  295.     rect.= 0;
  296.     rect.= pCodecCtx->width;
  297.     rect.= pCodecCtx->height;

  298.     packet = (AVPacket*)av_malloc(sizeof(AVPacket));
  299.     if(videoindex != -1)
  300.     {
  301.         img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
  302.         // img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUYV422, SWS_BICUBIC, NULL, NULL, NULL);
  303.         if(img_convert_ctx == NULL)
  304.         {
  305.             dbmsg("img_convert error");
  306.             return -1;
  307.         }
  308.     }
  309.     while( (av_read_frame(pFormatCtx, packet)>=0) && (signal_quit))
  310.     {
  311.         if(packet->stream_index == videoindex)
  312.         {
  313.             if((ret=avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, packet)) < 0)
  314.             {
  315.                 dbmsg("decocode video error");
  316.                 return -1;
  317.             }
  318.             if(frameFinished)
  319.             {
  320.                 SDL_LockYUVOverlay(overlay);
  321.                 pFrameYUV->data[0] = overlay->pixels[0];
  322.                 pFrameYUV->data[1] = overlay->pixels[2];
  323.                 pFrameYUV->data[2] = overlay->pixels[1];
  324.                 pFrameYUV->linesize[0] = overlay->pitches[0];
  325.                 pFrameYUV->linesize[1] = overlay->pitches[2];
  326.                 pFrameYUV->linesize[2] = overlay->pitches[1];
  327.                 sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, 
  328.                         pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); 
  329.                 SDL_UnlockYUVOverlay(overlay);
  330.                 SDL_DisplayYUVOverlay(overlay, &rect);
  331.                 SDL_Delay(40);
  332.             }
  333.         }
  334.         if(packet->stream_index == sndindex)
  335.         {
  336.             packet_queue_put(&audioq, packet);
  337.         }
  338.     }
  339.     SDL_WaitThread(sdl_thread, &ret);
  340.     SDL_DestroyMutex(affmutex);
  341.     av_free_packet(packet);
  342.     av_free(pFrameYUV);
  343.     av_free(pFrame);
  344.     avcodec_close(pCodecCtx);
  345.     avcodec_close(sndCodecCtx);
  346.     avformat_close_input(&pFormatCtx);
  347.     return 0;
  348. }
1.2 Makefile
  1. cong@msi:/work/ffmpeg/test/3sound$ cat Makefile 
  2. EXE=sound
  3. CC=gcc
  4. FFMPEG=/work/ffmpeg/out
  5. CFLAGS=--O0 -I$(FFMPEG)/include
  6. LDFLAGS = -L$(FFMPEG)/lib/ -lswscale -lswresample -lavformat -lavdevice -lavcodec -lavutil -lavfilter -lm -lSDL
  7. SRC=$(wildcard *.c)
  8. OBJ=$(patsubst %.c,%.o,$(SRC))
  9. DEP=$(patsubst %.c,.%.d,$(SRC))
  10. $(EXE):$(OBJ)
  11.     $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
  12. $(DEP):.%.d:%.c
  13.     @set -e; rm -f $@; \
  14.     $(CC) -MM $< > $@.$$$$; \
  15.     sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; \
  16.     rm -f $@.$$$$

  17. -include $(DEP)
  18. clean:
  19.     @rm $(EXE) $(OBJ) $(DEP) -f
  20. run:
  21.     export LD_LIBRARY_PATH=$(FFMPEG)/lib/ \
  22.     && ./$(EXE) ../resource/test.mp3
  23.     #&& ./$(EXE) ../resource/test.wav
  24.     #&& ./$(EXE) ../resource/test.wmv
  25.     #&& ./$(EXE) ../resource/test.rmvb
测试时发现只有wav格式的播放没有问题,

1.3 代码打包
3sound.rar (下载后改名为3sound.tar.gz)

二.改进
2.1 要改进的问题
只有wav播放没有问题,其它格式的播放时会有噪音,看了一下ffplay的代码现在都是用的AVFilter
2.2 代码
  1. cong@msi:/work/ffmpeg/test/3sound_1$ cat sound.
  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 SDL_AUDIO_BUFFER_SIZE 8192
  17. //#define AVCODEC_MAX_AUDIO_FRAME_SIZE 384000
  18. DECLARE_ALIGNED(16,uint8_t,audio_buf2) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
  19. struct SwrContext *swr_ctx = NULL;

  20. SDL_AudioSpec wanted_spec, spec;
  21. SDL_mutex *affmutex;
  22. SDL_Event sdlevent;
  23. int signal_quit = 1;
  24. enum AVSampleFormat audio_src_fmt;
  25. int64_t wanted_channel_layout;
  26. typedef struct PacketQueue
  27. {
  28.     AVPacketList * first_pkt, *last_pkt;
  29.     int nb_packets;
  30.     int size;
  31.     SDL_mutex *mutex;
  32.     SDL_cond * cond;
  33. }PacketQueue;
  34. PacketQueue audioq;

  35. static int eventThread(void* data)
  36. {
  37.     while(signal_quit)
  38.     {
  39.         SDL_LockMutex(affmutex);
  40.         while(SDL_PollEvent(&sdlevent))
  41.         {
  42.             switch(sdlevent.type)
  43.             {
  44.                 case SDL_QUIT:
  45.                     {
  46.                         signal_quit = 0;
  47.                     }
  48.                     break;
  49.                 default:
  50.                     break;

  51.             }
  52.         }
  53.         SDL_UnlockMutex(affmutex);
  54.     } 
  55. }
  56. void packet_queue_init(PacketQueue *q)
  57. {
  58.     memset(q, 0, sizeof(PacketQueue));
  59.     q->mutex = SDL_CreateMutex();
  60.     q->cond = SDL_CreateCond();
  61. }

  62. int packet_queue_put(PacketQueue *q, AVPacket *pkt)
  63. {

  64.     AVPacketList *pkt1;
  65.     if(av_dup_packet(pkt) < 0)
  66.         return -1;
  67.     pkt1 = av_malloc(sizeof(AVPacketList));
  68.     if (!pkt1)
  69.         return -1;
  70.     pkt1->pkt = *pkt;
  71.     pkt1->next = NULL;

  72.     SDL_LockMutex(q->mutex);

  73.     if (!q->last_pkt)
  74.         q->first_pkt = pkt1;
  75.     else
  76.         q->last_pkt->next = pkt1;
  77.     q->last_pkt = pkt1;
  78.     q->nb_packets++;
  79.     q->size += pkt1->pkt.size;
  80.     SDL_CondSignal(q->cond);

  81.     SDL_UnlockMutex(q->mutex);
  82.     return 0;
  83. }

  84. static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
  85. {
  86.     AVPacketList *pkt1;
  87.     int ret;
  88.     SDL_LockMutex(q->mutex);
  89.     for(;;)
  90.     {
  91.         if(== signal_quit)
  92.         {
  93.             ret = -1;
  94.             break;
  95.         }
  96.         pkt1 = q->first_pkt;
  97.         if (pkt1)
  98.         {
  99.             q->first_pkt = pkt1->next;
  100.             if (!q->first_pkt)
  101.                 q->last_pkt = NULL;
  102.             q->nb_packets--;
  103.             q->size -= pkt1->pkt.size;
  104.             *pkt = pkt1->pkt;
  105.             av_free(pkt1);
  106.             ret = 1;
  107.             break;
  108.         } else if (!block) {
  109.             ret = 0;
  110.             break;
  111.         } else {
  112.             SDL_CondWait(q->cond, q->mutex);
  113.         }
  114.     }
  115.     SDL_UnlockMutex(q->mutex);
  116.     return ret;
  117. }

  118. int audio_decode_frame(AVCodecContext *aCodecCtx, AVPacket *pkt, AVPacket *pkt_temp, AVFrame *frame)
  119. {
  120.     int i;
  121.     int len1,len2, data_size, got_frame;
  122.     int new_packet;
  123.     int64_t dec_channel_layout;
  124.     audio_src_fmt = AV_SAMPLE_FMT_S16; //AUDIO_S16SYS;
  125.     static once = 1;
  126.     uint8_t *out[] = { audio_buf2 };
  127.     for(;;)
  128.     {
  129.         while(pkt_temp->size>|| (!pkt_temp->data && new_packet))
  130.         {
  131.             if(!frame)
  132.             {
  133.                 if (!(frame = av_frame_alloc())) //av_frame_alloc(); //avcodec_alloc_frame
  134.                     return AVERROR(ENOMEM);
  135.             }
  136.             else
  137.             {
  138.                 dbmsg("av_get default frame");
  139.                 //avcodec_get_frame_defaults(frame);
  140.                 av_frame_unref(frame); //reset frame
  141.             }
  142.             new_packet = 0;
  143.             dbmsg();
  144.             len1 = avcodec_decode_audio4(aCodecCtx, frame, &got_frame, pkt_temp); //decode data is store in frame
  145.             if(len1 < 0)
  146.             {
  147.                 pkt_temp->size = 0;
  148.                 break;
  149.             }
  150.             //dbmsg("len1=%d, linesize=%d",len1, frame->linesize[0]);

  151.             pkt_temp->data += len1;
  152.             pkt_temp->size -= len1;
  153.             //这儿解码出来之后加入swr_convert
  154.             if(got_frame <= 0) /* No data yet, get more frames */
  155.                 continue;
  156.             //dbmsg("add filter: sample=%d", frame->nb_samples);
  157.             data_size = av_samples_get_buffer_size(NULL, aCodecCtx->channels, frame->nb_samples, aCodecCtx->sample_fmt, 1);
  158.             wanted_channel_layout = av_get_default_channel_layout(spec.channels);
  159.             dec_channel_layout = (frame->channel_layout && frame->channels==av_get_channel_layout_nb_channels(frame->channel_layout))?
  160.                 frame->channel_layout: wanted_channel_layout;

  161.             dbmsg("format=%d:%d,layout=%d:%d,rate=%d:%d,samples=%d:%d",frame->format,audio_src_fmt,
  162.                     dec_channel_layout,av_get_default_channel_layout(spec.channels),
  163.               frame->sample_rate,spec.freq,frame->nb_samples,spec.samples );
  164.             
  165.             dbmsg("wanted_channel_layout=%d", wanted_channel_layout);
  166.             dbmsg("audio_src_fmt=%d", audio_src_fmt);
  167.             dbmsg("spec.freq=%d", spec.freq);
  168.             //check: format,channel_layout,rate,sample
  169.             dbmsg("once =%d", once);
  170.             if((once) &&( (frame->format!=audio_src_fmt) || (dec_channel_layout!=av_get_default_channel_layout(spec.channels)) ||
  171.               (frame->sample_rate!=spec.freq) || (frame->nb_samples!=spec.samples)) )
  172.             {
  173.                 dbmsg();
  174.                 if(swr_ctx != NULL)
  175.                     swr_free(&swr_ctx);
  176.                 dbmsg("wanted_channel_layout=%d, audio_src_fmt=%d, frame->sample_rate=%d, dec_channel_layout=%d, frame->format=%d, frame->sample_rate=%d",wanted_channel_layout, audio_src_fmt, frame->sample_rate,dec_channel_layout, frame->format, frame->sample_rate);
  177.                 swr_ctx = swr_alloc_set_opts(NULL, wanted_channel_layout, audio_src_fmt, frame->sample_rate, dec_channel_layout, frame->format, frame->sample_rate, 0, NULL);
  178.                 if(swr_ctx == NULL)
  179.                 {
  180.                     dbmsg("swr_ctx == NULL");
  181.                 }
  182.                 swr_init(swr_ctx);
  183.                 dbmsg();
  184.                 once = 0;
  185.             }
  186.             if(swr_ctx)
  187.             {
  188.                 len2 = swr_convert(swr_ctx, out, sizeof(audio_buf2)/spec.channels/av_get_bytes_per_sample(frame->format),(const uint8_t **)frame->extended_data, frame->nb_samples);
  189.                 dbmsg("needed swr_onvert, len2=%d", len2);
  190.                 data_size = len2 * spec.channels * av_get_bytes_per_sample(audio_src_fmt);
  191.             }else {
  192.                 memcpy(audio_buf2, frame->data[0], frame->linesize[0]);
  193.             }

  194.             dbmsg("data_size =%d", data_size);
  195.             return data_size;
  196.         }
  197.         if(pkt->data)
  198.             av_free_packet(pkt);
  199.         memset(pkt_temp, 0, sizeof(*pkt_temp));
  200.         if(== signal_quit)
  201.             return -1;

  202.         if((new_packet = packet_queue_get(&audioq, pkt, 1)) < 0)
  203.             return -1;
  204.         *pkt_temp = *pkt;
  205.     }
  206. }

  207. void audio_callback(void *userdata, Uint8 *stream, int len)
  208. {
  209.     int i;
  210.     AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
  211.     int len1, audio_size;

  212.     static unsigned int audio_buf_size = 0;
  213.     static unsigned int audio_buf_index = 0;

  214.     AVPacket *pkt = av_mallocz(sizeof(AVPacket));
  215.     AVPacket *pkt_temp = av_mallocz(sizeof(AVPacket));
  216.     AVFrame *frame = NULL;
  217.     dbmsg("len=%d", len);
  218.     while(len > 0)
  219.     {
  220.         if(audio_buf_index >= audio_buf_size)
  221.         {
  222.             audio_size = audio_decode_frame(aCodecCtx, pkt, pkt_temp, frame);
  223.             dbmsg("audio_size=%d", audio_size);
  224.             if(audio_size < 0)
  225.             {
  226.                 /* If error, output silence */
  227.                 audio_buf_size = 1024;
  228.                 memset(audio_buf2, 0, audio_buf_size);
  229.             } else {
  230.                 audio_buf_size = audio_size;
  231.             }
  232.             audio_buf_index = 0;
  233.         }
  234.         //dbmsg("len=%d, audio_buf_size=%d, audio_buf_index=%d", len, audio_buf_size, audio_buf_index);
  235.         len1 = audio_buf_size - audio_buf_index;
  236.         //dbmsg("len1=%d", len1);
  237.         if(len1 > len)
  238.             len1 = len;
  239.         //dbmsg("len1 = %d", len1);
  240.         memcpy(stream, (uint8_t *)audio_buf2 + audio_buf_index, len1);
  241.         len -= len1;
  242.         stream += len1;
  243.         audio_buf_index += len1;
  244.     }
  245. }

  246. int main(int argc, char **argv)
  247. {
  248.     int i=0;
  249.     int ret;
  250.     int videoindex= -1;
  251.     int sndindex= -1;
  252.     int frameFinished;
  253.     AVFormatContext *pFormatCtx = NULL;
  254.     AVCodecContext * pCodecCtx;
  255.     AVCodecContext * sndCodecCtx;
  256.     AVCodec * pCodec;
  257.     AVCodec * sndCodec;
  258.     AVFrame * pFrame;
  259.     AVFrame * pFrameYUV;
  260.     AVPacket * packet; 
  261.     struct SwsContext *img_convert_ctx;

  262.     SDL_Surface* psscreen;
  263.     SDL_Overlay* overlay;
  264.     SDL_Rect rect;
  265.     SDL_Thread* sdl_thread;

  266.     avcodec_register_all();
  267.     avfilter_register_all();
  268.     av_register_all();

  269.     pFormatCtx = avformat_alloc_context();

  270.     if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
  271.         return -1; 

  272.     if(avformat_find_stream_info(pFormatCtx, NULL)<0)
  273.         return -1;
  274.     av_dump_format(pFormatCtx,0, 0, 0);

  275.     for(i=0; i<pFormatCtx->nb_streams; i++)
  276.     {
  277.         if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
  278.         {
  279.             videoindex= i;
  280.         }
  281.         if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
  282.         {
  283.             sndindex= i;
  284.         }
  285.     }
  286.     if(videoindex== -1)
  287.     {
  288.         dbmsg("no video stream found!");
  289.     }
  290.     if(sndindex== -1)
  291.     {
  292.         dbmsg("no sound stream found!");
  293.     }
  294.     dbmsg("videoindex=%d, sndindex=%d", videoindex, sndindex);
  295.     if(videoindex != -1)
  296.     {
  297.         pCodecCtx = pFormatCtx->streams[videoindex]->codec;
  298.         pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
  299.         if(pCodec == NULL)
  300.         {
  301.             dbmsg("Codec not found");
  302.             return -1;
  303.         }
  304.         if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
  305.             return -1;
  306.         pFrame = av_frame_alloc(); //avcodec_alloc_frame
  307.         pFrameYUV = av_frame_alloc();

  308.         SDL_Init(SDL_INIT_EVERYTHING);
  309.         psscreen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, SDL_SWSURFACE);
  310.         SDL_WM_SetCaption( "FFMPEG Window", NULL);
  311.         overlay = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, psscreen);
  312.         //overlay = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YUY2_OVERLAY, psscreen);
  313.     }
  314.     if(sndindex != -1)
  315.     {
  316.         sndCodecCtx = pFormatCtx->streams[sndindex]->codec;
  317.         sndCodec = avcodec_find_decoder(sndCodecCtx->codec_id);
  318.         if(sndCodec == NULL)
  319.         {
  320.             dbmsg("Codec not found");
  321.             return -1;
  322.         }
  323.         if(avcodec_open2(sndCodecCtx, sndCodec, NULL) < 0)
  324.             return -1;
  325.     
  326.         wanted_spec.freq = sndCodecCtx->sample_rate;
  327.         wanted_spec.format = AUDIO_S16SYS;
  328.         wanted_spec.channels = sndCodecCtx->channels;
  329.         wanted_spec.silence = 0;
  330.         wanted_spec.samples = 2048;
  331.         wanted_spec.callback = audio_callback;
  332.         wanted_spec.userdata = sndCodecCtx;
  333.         if(SDL_OpenAudio(&wanted_spec, &spec) < 0)
  334.         {
  335.             dbmsg("SDL_OpenAudio:%s", SDL_GetError());
  336.             return -1;
  337.         }
  338.         dbmsg("freq=%d, channels=%d, samples=%d", spec.freq, spec.channels, spec.samples);
  339.         packet_queue_init(&audioq);
  340.         SDL_PauseAudio(0);
  341.     }
  342.     //sdl get signal quit
  343.     affmutex = SDL_CreateMutex();
  344.     sdl_thread = SDL_CreateThread(eventThread, NULL);

  345.     rect.= 0;
  346.     rect.= 0;
  347.     rect.= pCodecCtx->width;
  348.     rect.= pCodecCtx->height;

  349.     packet = (AVPacket*)av_malloc(sizeof(AVPacket));
  350.     if(videoindex != -1)
  351.     {
  352.         img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
  353.         // img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUYV422, SWS_BICUBIC, NULL, NULL, NULL);
  354.         if(img_convert_ctx == NULL)
  355.         {
  356.             dbmsg("img_convert error");
  357.             return -1;
  358.         }
  359.     }
  360.     while( (av_read_frame(pFormatCtx, packet)>=0) && (signal_quit))
  361.     {
  362.         if(packet->stream_index == videoindex)
  363.         {
  364.             dbmsg();
  365.             if((ret=avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, packet)) < 0)
  366.             {
  367.                 dbmsg("decocode video error");
  368.                 return -1;
  369.             }
  370.             if(frameFinished)
  371.             {
  372.                 SDL_LockYUVOverlay(overlay);
  373.                 pFrameYUV->data[0] = overlay->pixels[0];
  374.                 pFrameYUV->data[1] = overlay->pixels[2];
  375.                 pFrameYUV->data[2] = overlay->pixels[1];
  376.                 pFrameYUV->linesize[0] = overlay->pitches[0];
  377.                 pFrameYUV->linesize[1] = overlay->pitches[2];
  378.                 pFrameYUV->linesize[2] = overlay->pitches[1];
  379.                 sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, 
  380.                         pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); 
  381.                 SDL_UnlockYUVOverlay(overlay);
  382.                 SDL_DisplayYUVOverlay(overlay, &rect);
  383.                 SDL_Delay(40);
  384.             }
  385.         }
  386.         if(packet->stream_index == sndindex)
  387.         {
  388.             packet_queue_put(&audioq, packet);
  389.         }
  390.     }
  391.     SDL_WaitThread(sdl_thread, &ret);
  392.     SDL_DestroyMutex(affmutex);
  393.     av_free_packet(packet);
  394.     av_free(pFrameYUV);
  395.     av_free(pFrame);
  396.     avcodec_close(pCodecCtx);
  397.     avcodec_close(sndCodecCtx);
  398.     avformat_close_input(&pFormatCtx);
  399.     return 0;
  400. }
  401. cong@msi:/work/ffmpeg/test/3sound_1$
2.3 代码打包
3sound_1.rar (下载后改名为3sound_1.tar.gz)
三.代码
3.1 再次改进
上面的代码太乱了,有很多的全局变量,下面整理一下,学习ffplay做成一个结构体


附录:1.测试的文件格式说明
  1. test.rmvb--> 
  2.     Stream 0
  3.         Type: Audio
  4.         Codec: Cook Auidio(cook)
  5.         Channels: Stereo
  6.         Sample rate: 44100HZ
  7.         Bits per sample: 32
  8.     Stream 1
  9.         Type: Video
  10.         Codec: RealVideo 9/10(4.0)(RV40)
  11.         Resolution: 1024*576
  12.         Decoded format: Planar 4:2:0 YUV


  13. test.wmv -->
  14.     Stream 0 
  15.         Type: Video
  16.         Codec: Windows Media Video 9 (WMV3)
  17.         Language: Chinese
  18.         Resolution: 620x466
  19.         Frame rate: 5
  20.         Decoded format: Planar 4:2:0 YUV
  21.     Stream 1
  22.         Type: Audio
  23.         Codec: Windows Media Audio 2 (WMA2)
  24.         Language: Chinese
  25.         Channels: Mono
  26.         Sample rate: 22050 Hz
  27.         Bits per sample: 32
  28. test.mp3 -->
  29.     Type: Audio
  30.     Codec: MPEG Audio layer 1/2/(mpga)
  31.     Channels: Stereo
  32.     Sample rate: 44100 Hz
  33.     Bitrate: 192 kb/s
  34. test.wav -->
  35.     Type: Audio
  36.     Codec: PCM S16 LE (s16l)
  37.     Channels: Stereo
  38.     Sample rate: 44100 Hz
  39.     Bits per sample: 16


0 0