ffmpeg学习---4.Playing Sound
来源:互联网 发布:变频器模拟软件 编辑:程序博客网 时间:2024/06/14 07:46
一.最原始版的
http://dranger.com/ffmpeg/tutorial03.html
1. 3playsound.c
1.2 Makefile
测试时发现只有wav格式的播放没有问题,
1.3 代码打包
3sound.rar (下载后改名为3sound.tar.gz)
二.改进
2.1 要改进的问题
只有wav播放没有问题,其它格式的播放时会有噪音,看了一下ffplay的代码现在都是用的AVFilter
2.2 代码
2.3 代码打包
3sound_1.rar (下载后改名为3sound_1.tar.gz)
三.代码
3.1 再次改进
上面的代码太乱了,有很多的全局变量,下面整理一下,学习ffplay做成一个结构体
附录:1.测试的文件格式说明
http://dranger.com/ffmpeg/tutorial03.html
1. 3playsound.c
- cong@msi:/work/ffmpeg/test/4sound$ cat sound.c
- #include "utils.h"
- #include <libavformat/avformat.h>
- #include <libswscale/swscale.h>
- #include <SDL/SDL.h>
- #define SDL_AUDIO_BUFFER_SIZE 4096
- #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
- SDL_mutex *affmutex;
- SDL_Event sdlevent;
- int signal_quit = 1;
- typedef struct PacketQueue
- {
- AVPacketList * first_pkt, *last_pkt;
- int nb_packets;
- int size;
- SDL_mutex *mutex;
- SDL_cond * cond;
- }PacketQueue;
- PacketQueue audioq;
- static int eventThread(void* data)
- {
- while(signal_quit)
- {
- SDL_LockMutex(affmutex);
- while(SDL_PollEvent(&sdlevent))
- {
- switch(sdlevent.type)
- {
- case SDL_QUIT:
- {
- signal_quit = 0;
- }
- break;
- default:
- break;
- }
- }
- SDL_UnlockMutex(affmutex);
- }
- }
- void packet_queue_init(PacketQueue *q)
- {
- memset(q, 0, sizeof(PacketQueue));
- q->mutex = SDL_CreateMutex();
- q->cond = SDL_CreateCond();
- }
- int packet_queue_put(PacketQueue *q, AVPacket *pkt)
- {
- AVPacketList *pkt1;
- if(av_dup_packet(pkt) < 0)
- return -1;
- pkt1 = av_malloc(sizeof(AVPacketList));
- if (!pkt1)
- return -1;
- pkt1->pkt = *pkt;
- pkt1->next = NULL;
- SDL_LockMutex(q->mutex);
- if (!q->last_pkt)
- q->first_pkt = pkt1;
- else
- q->last_pkt->next = pkt1;
- q->last_pkt = pkt1;
- q->nb_packets++;
- q->size += pkt1->pkt.size;
- SDL_CondSignal(q->cond);
- SDL_UnlockMutex(q->mutex);
- return 0;
- }
- static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
- {
- AVPacketList *pkt1;
- int ret;
- SDL_LockMutex(q->mutex);
- for(;;)
- {
- if(0 == signal_quit)
- {
- ret = -1;
- break;
- }
- pkt1 = q->first_pkt;
- if (pkt1)
- {
- q->first_pkt = pkt1->next;
- if (!q->first_pkt)
- q->last_pkt = NULL;
- q->nb_packets--;
- q->size -= pkt1->pkt.size;
- *pkt = pkt1->pkt;
- av_free(pkt1);
- ret = 1;
- break;
- } else if (!block) {
- ret = 0;
- break;
- } else {
- SDL_CondWait(q->cond, q->mutex);
- }
- }
- SDL_UnlockMutex(q->mutex);
- return ret;
- }
- int audio_decode_frame(AVCodecContext *aCodecCtx, AVPacket *pkt, AVPacket *pkt_temp, AVFrame *frame, uint8_t *audio_buf)
- {
- int i;
- int len1, data_size, got_frame;
- int new_packet;
- for(;;)
- {
- while(pkt_temp->size>0 || (!pkt_temp->data && new_packet))
- {
- if(!frame)
- {
- if (!(frame = av_frame_alloc())) //函数avcodec_alloc_frame不用了
- return AVERROR(ENOMEM);
- }
- else
- {
- av_frame_unref(frame); //函数avcodec_get_frame_defaults(frame)不用了
- }
- new_packet = 0;
- len1 = avcodec_decode_audio4(aCodecCtx, frame, &got_frame, pkt_temp); //decode data is store in frame
- if(len1 < 0)
- {
- pkt_temp->size = 0;
- break;
- }
- pkt_temp->data += len1;
- pkt_temp->size -= len1;
- if(got_frame <= 0) /* No data yet, get more frames */
- continue;
- //dbmsg("add filter: sample=%d", frame->nb_samples); //这个地方有问题:若解码后的数据包与sdl需要的数据格式不匹配则播放产生噪声
- data_size = av_samples_get_buffer_size(NULL, aCodecCtx->channels, frame->nb_samples, aCodecCtx->sample_fmt, 1);
- memcpy(audio_buf, frame->data[0], frame->linesize[0]);
- return data_size;
- }
- if(pkt->data)
- av_free_packet(pkt);
- memset(pkt_temp, 0, sizeof(*pkt_temp));
- if(0 == signal_quit)
- return -1;
- //这个地方是本函数的开始位置,一直等侍音频数据包的到来
- if((new_packet = packet_queue_get(&audioq, pkt, 1)) < 0)
- return -1;
- *pkt_temp = *pkt;
- }
- }
- void audio_callback(void *userdata, Uint8 *stream, int len) //这个回调函数中len=4096
- {
- int i;
- AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
- int len1, audio_size;
- static uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2];
- static unsigned int audio_buf_size = 0;
- static unsigned int audio_buf_index = 0;
- AVPacket *pkt = av_mallocz(sizeof(AVPacket));
- AVPacket *pkt_temp = av_mallocz(sizeof(AVPacket));
- AVFrame *frame = NULL;
- //dbmsg("len=%d", len);
- while(len > 0)
- {
- if(audio_buf_index >= audio_buf_size)
- { //如果没有音频数据包则等侍,若有数据包则解码,并将解码后的数据放在audio_buf中
- audio_size = audio_decode_frame(aCodecCtx, pkt, pkt_temp, frame, audio_buf);
- if(audio_size < 0)
- {
- /* If error, output silence */
- audio_buf_size = 1024;
- memset(audio_buf, 0, audio_buf_size);
- } else {
- audio_buf_size = audio_size;
- }
- audio_buf_index = 0;
- }
- len1 = audio_buf_size - audio_buf_index;
- if(len1 > len)
- len1 = len;
- //将解码后的数据(audio_buf中的数据)copy到stream中进行播放
- memcpy(stream, (uint8_t *)audio_buf + audio_buf_index, len1);
- len -= len1;
- stream += len1;
- audio_buf_index += len1;
- }
- }
- int main(int argc, char **argv)
- {
- int i=0;
- int ret;
- int videoindex= -1;
- int sndindex= -1;
- int frameFinished;
- AVFormatContext *pFormatCtx = NULL;
- AVCodecContext * pCodecCtx;
- AVCodecContext * sndCodecCtx;
- AVCodec * pCodec;
- AVCodec * sndCodec;
- AVFrame * pFrame;
- AVFrame * pFrameYUV;
- AVPacket * packet;
- struct SwsContext *img_convert_ctx;
- SDL_Surface* psscreen;
- SDL_Overlay* overlay;
- SDL_Rect rect;
- SDL_Thread* sdl_thread;
- SDL_AudioSpec wanted_spec, spec;
- //a. ffmpeg的初始化(虽然名字是register就这么说吧)
- avcodec_register_all();
- avfilter_register_all();
- av_register_all();
- //b.打开视频文件
- pFormatCtx = avformat_alloc_context();
- if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
- return -1;
- //c.获取视频文件的流信息,(即查看有几个视频流几个音频流)
if(avformat_find_stream_info(pFormatCtx, NULL)<0) - return -1;
- av_dump_format(pFormatCtx,0, 0, 0);
- //d.获取了视频流的index,这样以后读取一帧之后,根据索引号才能判断这一帧是不是视频帧
- //同理获取了音频流的index,这样以后读取一包之后,根据索引号才能判断这一帧是不是音频帧
- for(i=0; i<pFormatCtx->nb_streams; i++)
- {
- if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
- {
- videoindex= i; //获取视频流的索引
- }
- if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- {
- sndindex= i; //获取视频流的索引
- }
- }
- if(videoindex== -1)
- {
- dbmsg("no video stream found!");
- //return -1;
- }
- if(sndindex== -1)
- {
- dbmsg("no sound stream found!");
- return -1;
- }
- //e.1为视频流寻找解码器:在c中不仅有视频流的index,还有视频流的编码codec_id,并打开解码器
- if(videoindex != -1)
- {
- pCodecCtx = pFormatCtx->streams[videoindex]->codec;
- pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
- if(pCodec == NULL)
- {
- dbmsg("Codec not found");
- return -1;
- }
- if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
- return -1;
- }
- //e.2为音频流寻找解码器,并打开解码器
- if(sndindex != -1)
- {
- sndCodecCtx = pFormatCtx->streams[sndindex]->codec;
- sndCodec = avcodec_find_decoder(sndCodecCtx->codec_id);
- if(sndCodec == NULL)
- {
- dbmsg("Codec not found");
- return -1;
- }
- if(avcodec_open2(sndCodecCtx, sndCodec, NULL) < 0)
- return -1;
- }
- //f.1视频显示的准备:SDL初始化,设置显示模式,创建画布
- pFrame = av_frame_alloc(); //以前的avcodec_alloc_frame函数现在不用了
- pFrameYUV = av_frame_alloc(); //以前的avcodec_alloc_frame函数现在不用了
- SDL_Init(SDL_INIT_EVERYTHING);
- psscreen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, SDL_SWSURFACE);
- SDL_WM_SetCaption( "FFMPEG Window", NULL);
- //注意这儿的参数SDL_YU12_OVERLAY与SDL_YUY2_OVERLAY一定要与下面sws_scale中的参数配套
- overlay = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, psscreen);
- //overlay = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YUY2_OVERLAY, psscreen);
- //f.2音频的准备:设置输出audio的格式
- wanted_spec.freq = sndCodecCtx->sample_rate; //采样率
- wanted_spec.format = AUDIO_S16SYS; //SDL中的输入格式, s代表signed有符号的,16代表采样是16位的采样精度,SYS代表大小端格式按照系统默认
- wanted_spec.channels = sndCodecCtx->channels; //声道数
- wanted_spec.silence = 0; //需不需要静音: 0不需要,但是设为之后仍旧是有声音的,看来这个理解有误,有明白的告诉一下?????
- wanted_spec.samples = 2048; //audio_buffer的size,通常这个值设为512到8192,ffplay设置的是1024
- wanted_spec.callback = audio_callback; //回调函数
- wanted_spec.userdata = sndCodecCtx; //给回调函数传的参数
- if(SDL_OpenAudio(&wanted_spec, &spec) < 0)
- {
- dbmsg("SDL_OpenAudio:%s", SDL_GetError());
- return -1;
- }
- packet_queue_init(&audioq);
- SDL_PauseAudio(0);
- //与SDL的退出相关
- affmutex = SDL_CreateMutex();
- sdl_thread = SDL_CreateThread(eventThread, NULL);
- rect.x = 0;
- rect.y = 0;
- rect.w = pCodecCtx->width;
- rect.h = pCodecCtx->height;
- packet = (AVPacket*)av_malloc(sizeof(AVPacket));
- if(videoindex != -1)
- {
- img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
- // img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUYV422, SWS_BICUBIC, NULL, NULL, NULL);
- if(img_convert_ctx == NULL)
- {
- dbmsg("img_convert error");
- return -1;
- }
- }
- while( (av_read_frame(pFormatCtx, packet)>=0) && (signal_quit))
- {
- if(packet->stream_index == videoindex)
- {
- if((ret=avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, packet)) < 0)
- {
- dbmsg("decocode video error");
- return -1;
- }
- if(frameFinished)
- {
- SDL_LockYUVOverlay(overlay);
- pFrameYUV->data[0] = overlay->pixels[0];
- pFrameYUV->data[1] = overlay->pixels[2];
- pFrameYUV->data[2] = overlay->pixels[1];
- pFrameYUV->linesize[0] = overlay->pitches[0];
- pFrameYUV->linesize[1] = overlay->pitches[2];
- pFrameYUV->linesize[2] = overlay->pitches[1];
- sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0,
- pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
- SDL_UnlockYUVOverlay(overlay);
- SDL_DisplayYUVOverlay(overlay, &rect);
- SDL_Delay(40);
- }
- }
- if(packet->stream_index == sndindex)
- {
- packet_queue_put(&audioq, packet);
- }
- }
- SDL_WaitThread(sdl_thread, &ret);
- SDL_DestroyMutex(affmutex);
- av_free_packet(packet);
- av_free(pFrameYUV);
- av_free(pFrame);
- avcodec_close(pCodecCtx);
- avcodec_close(sndCodecCtx);
- avformat_close_input(&pFormatCtx);
- return 0;
- }
- cong@msi:/work/ffmpeg/test/3sound$ cat Makefile
- EXE=sound
- CC=gcc
- FFMPEG=/work/ffmpeg/out
- CFLAGS=-g -O0 -I$(FFMPEG)/include
- LDFLAGS = -L$(FFMPEG)/lib/ -lswscale -lswresample -lavformat -lavdevice -lavcodec -lavutil -lavfilter -lm -lSDL
- SRC=$(wildcard *.c)
- OBJ=$(patsubst %.c,%.o,$(SRC))
- DEP=$(patsubst %.c,.%.d,$(SRC))
- $(EXE):$(OBJ)
- $(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS)
- $(DEP):.%.d:%.c
- @set -e; rm -f $@; \
- $(CC) -MM $< > $@.$$$$; \
- sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; \
- rm -f $@.$$$$
- -include $(DEP)
- clean:
- @rm $(EXE) $(OBJ) $(DEP) -f
- run:
- export LD_LIBRARY_PATH=$(FFMPEG)/lib/ \
- && ./$(EXE) ../resource/test.mp3
- #&& ./$(EXE) ../resource/test.wav
- #&& ./$(EXE) ../resource/test.wmv
- #&& ./$(EXE) ../resource/test.rmvb
1.3 代码打包
3sound.rar (下载后改名为3sound.tar.gz)
二.改进
2.1 要改进的问题
只有wav播放没有问题,其它格式的播放时会有噪音,看了一下ffplay的代码现在都是用的AVFilter
2.2 代码
- cong@msi:/work/ffmpeg/test/3sound_1$ cat sound.c
- #include "utils.h"
- #include <libavcodec/avcodec.h>
- #include <libavformat/avformat.h>
- #include <libswscale/swscale.h>
- #include <libswresample/swresample.h>
- #include <libavutil/avstring.h>
- #include <libavutil/pixfmt.h>
- #include <libavutil/log.h>
- #include <SDL/SDL.h>
- #include <SDL/SDL_thread.h>
- #include <stdio.h>
- #include <math.h>
- #define SDL_AUDIO_BUFFER_SIZE 4096
- #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
- //#define SDL_AUDIO_BUFFER_SIZE 8192
- //#define AVCODEC_MAX_AUDIO_FRAME_SIZE 384000
- DECLARE_ALIGNED(16,uint8_t,audio_buf2) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
- struct SwrContext *swr_ctx = NULL;
- SDL_AudioSpec wanted_spec, spec;
- SDL_mutex *affmutex;
- SDL_Event sdlevent;
- int signal_quit = 1;
- enum AVSampleFormat audio_src_fmt;
- int64_t wanted_channel_layout;
- typedef struct PacketQueue
- {
- AVPacketList * first_pkt, *last_pkt;
- int nb_packets;
- int size;
- SDL_mutex *mutex;
- SDL_cond * cond;
- }PacketQueue;
- PacketQueue audioq;
- static int eventThread(void* data)
- {
- while(signal_quit)
- {
- SDL_LockMutex(affmutex);
- while(SDL_PollEvent(&sdlevent))
- {
- switch(sdlevent.type)
- {
- case SDL_QUIT:
- {
- signal_quit = 0;
- }
- break;
- default:
- break;
- }
- }
- SDL_UnlockMutex(affmutex);
- }
- }
- void packet_queue_init(PacketQueue *q)
- {
- memset(q, 0, sizeof(PacketQueue));
- q->mutex = SDL_CreateMutex();
- q->cond = SDL_CreateCond();
- }
- int packet_queue_put(PacketQueue *q, AVPacket *pkt)
- {
- AVPacketList *pkt1;
- if(av_dup_packet(pkt) < 0)
- return -1;
- pkt1 = av_malloc(sizeof(AVPacketList));
- if (!pkt1)
- return -1;
- pkt1->pkt = *pkt;
- pkt1->next = NULL;
- SDL_LockMutex(q->mutex);
- if (!q->last_pkt)
- q->first_pkt = pkt1;
- else
- q->last_pkt->next = pkt1;
- q->last_pkt = pkt1;
- q->nb_packets++;
- q->size += pkt1->pkt.size;
- SDL_CondSignal(q->cond);
- SDL_UnlockMutex(q->mutex);
- return 0;
- }
- static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block)
- {
- AVPacketList *pkt1;
- int ret;
- SDL_LockMutex(q->mutex);
- for(;;)
- {
- if(0 == signal_quit)
- {
- ret = -1;
- break;
- }
- pkt1 = q->first_pkt;
- if (pkt1)
- {
- q->first_pkt = pkt1->next;
- if (!q->first_pkt)
- q->last_pkt = NULL;
- q->nb_packets--;
- q->size -= pkt1->pkt.size;
- *pkt = pkt1->pkt;
- av_free(pkt1);
- ret = 1;
- break;
- } else if (!block) {
- ret = 0;
- break;
- } else {
- SDL_CondWait(q->cond, q->mutex);
- }
- }
- SDL_UnlockMutex(q->mutex);
- return ret;
- }
- int audio_decode_frame(AVCodecContext *aCodecCtx, AVPacket *pkt, AVPacket *pkt_temp, AVFrame *frame)
- {
- int i;
- int len1,len2, data_size, got_frame;
- int new_packet;
- int64_t dec_channel_layout;
- audio_src_fmt = AV_SAMPLE_FMT_S16; //AUDIO_S16SYS;
- static once = 1;
- uint8_t *out[] = { audio_buf2 };
- for(;;)
- {
- while(pkt_temp->size>0 || (!pkt_temp->data && new_packet))
- {
- if(!frame)
- {
- if (!(frame = av_frame_alloc())) //av_frame_alloc(); //avcodec_alloc_frame
- return AVERROR(ENOMEM);
- }
- else
- {
- dbmsg("av_get default frame");
- //avcodec_get_frame_defaults(frame);
- av_frame_unref(frame); //reset frame
- }
- new_packet = 0;
- dbmsg();
- len1 = avcodec_decode_audio4(aCodecCtx, frame, &got_frame, pkt_temp); //decode data is store in frame
- if(len1 < 0)
- {
- pkt_temp->size = 0;
- break;
- }
- //dbmsg("len1=%d, linesize=%d",len1, frame->linesize[0]);
- pkt_temp->data += len1;
- pkt_temp->size -= len1;
- //这儿解码出来之后加入swr_convert
- if(got_frame <= 0) /* No data yet, get more frames */
- continue;
- //dbmsg("add filter: sample=%d", frame->nb_samples);
- data_size = av_samples_get_buffer_size(NULL, aCodecCtx->channels, frame->nb_samples, aCodecCtx->sample_fmt, 1);
- wanted_channel_layout = av_get_default_channel_layout(spec.channels);
- dec_channel_layout = (frame->channel_layout && frame->channels==av_get_channel_layout_nb_channels(frame->channel_layout))?
- frame->channel_layout: wanted_channel_layout;
- dbmsg("format=%d:%d,layout=%d:%d,rate=%d:%d,samples=%d:%d",frame->format,audio_src_fmt,
- dec_channel_layout,av_get_default_channel_layout(spec.channels),
- frame->sample_rate,spec.freq,frame->nb_samples,spec.samples );
-
- dbmsg("wanted_channel_layout=%d", wanted_channel_layout);
- dbmsg("audio_src_fmt=%d", audio_src_fmt);
- dbmsg("spec.freq=%d", spec.freq);
- //check: format,channel_layout,rate,sample
- dbmsg("once =%d", once);
- if((once) &&( (frame->format!=audio_src_fmt) || (dec_channel_layout!=av_get_default_channel_layout(spec.channels)) ||
- (frame->sample_rate!=spec.freq) || (frame->nb_samples!=spec.samples)) )
- {
- dbmsg();
- if(swr_ctx != NULL)
- swr_free(&swr_ctx);
- 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);
- 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);
- if(swr_ctx == NULL)
- {
- dbmsg("swr_ctx == NULL");
- }
- swr_init(swr_ctx);
- dbmsg();
- once = 0;
- }
- if(swr_ctx)
- {
- 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);
- dbmsg("needed swr_onvert, len2=%d", len2);
- data_size = len2 * spec.channels * av_get_bytes_per_sample(audio_src_fmt);
- }else {
- memcpy(audio_buf2, frame->data[0], frame->linesize[0]);
- }
- dbmsg("data_size =%d", data_size);
- return data_size;
- }
- if(pkt->data)
- av_free_packet(pkt);
- memset(pkt_temp, 0, sizeof(*pkt_temp));
- if(0 == signal_quit)
- return -1;
- if((new_packet = packet_queue_get(&audioq, pkt, 1)) < 0)
- return -1;
- *pkt_temp = *pkt;
- }
- }
- void audio_callback(void *userdata, Uint8 *stream, int len)
- {
- int i;
- AVCodecContext *aCodecCtx = (AVCodecContext *)userdata;
- int len1, audio_size;
- static unsigned int audio_buf_size = 0;
- static unsigned int audio_buf_index = 0;
- AVPacket *pkt = av_mallocz(sizeof(AVPacket));
- AVPacket *pkt_temp = av_mallocz(sizeof(AVPacket));
- AVFrame *frame = NULL;
- dbmsg("len=%d", len);
- while(len > 0)
- {
- if(audio_buf_index >= audio_buf_size)
- {
- audio_size = audio_decode_frame(aCodecCtx, pkt, pkt_temp, frame);
- dbmsg("audio_size=%d", audio_size);
- if(audio_size < 0)
- {
- /* If error, output silence */
- audio_buf_size = 1024;
- memset(audio_buf2, 0, audio_buf_size);
- } else {
- audio_buf_size = audio_size;
- }
- audio_buf_index = 0;
- }
- //dbmsg("len=%d, audio_buf_size=%d, audio_buf_index=%d", len, audio_buf_size, audio_buf_index);
- len1 = audio_buf_size - audio_buf_index;
- //dbmsg("len1=%d", len1);
- if(len1 > len)
- len1 = len;
- //dbmsg("len1 = %d", len1);
- memcpy(stream, (uint8_t *)audio_buf2 + audio_buf_index, len1);
- len -= len1;
- stream += len1;
- audio_buf_index += len1;
- }
- }
- int main(int argc, char **argv)
- {
- int i=0;
- int ret;
- int videoindex= -1;
- int sndindex= -1;
- int frameFinished;
- AVFormatContext *pFormatCtx = NULL;
- AVCodecContext * pCodecCtx;
- AVCodecContext * sndCodecCtx;
- AVCodec * pCodec;
- AVCodec * sndCodec;
- AVFrame * pFrame;
- AVFrame * pFrameYUV;
- AVPacket * packet;
- struct SwsContext *img_convert_ctx;
- SDL_Surface* psscreen;
- SDL_Overlay* overlay;
- SDL_Rect rect;
- SDL_Thread* sdl_thread;
- avcodec_register_all();
- avfilter_register_all();
- av_register_all();
- pFormatCtx = avformat_alloc_context();
- if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
- return -1;
- if(avformat_find_stream_info(pFormatCtx, NULL)<0)
- return -1;
- av_dump_format(pFormatCtx,0, 0, 0);
- for(i=0; i<pFormatCtx->nb_streams; i++)
- {
- if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
- {
- videoindex= i;
- }
- if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
- {
- sndindex= i;
- }
- }
- if(videoindex== -1)
- {
- dbmsg("no video stream found!");
- }
- if(sndindex== -1)
- {
- dbmsg("no sound stream found!");
- }
- dbmsg("videoindex=%d, sndindex=%d", videoindex, sndindex);
- if(videoindex != -1)
- {
- pCodecCtx = pFormatCtx->streams[videoindex]->codec;
- pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
- if(pCodec == NULL)
- {
- dbmsg("Codec not found");
- return -1;
- }
- if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
- return -1;
- pFrame = av_frame_alloc(); //avcodec_alloc_frame
- pFrameYUV = av_frame_alloc();
- SDL_Init(SDL_INIT_EVERYTHING);
- psscreen = SDL_SetVideoMode(pCodecCtx->width, pCodecCtx->height, 0, SDL_SWSURFACE);
- SDL_WM_SetCaption( "FFMPEG Window", NULL);
- overlay = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YV12_OVERLAY, psscreen);
- //overlay = SDL_CreateYUVOverlay(pCodecCtx->width, pCodecCtx->height, SDL_YUY2_OVERLAY, psscreen);
- }
- if(sndindex != -1)
- {
- sndCodecCtx = pFormatCtx->streams[sndindex]->codec;
- sndCodec = avcodec_find_decoder(sndCodecCtx->codec_id);
- if(sndCodec == NULL)
- {
- dbmsg("Codec not found");
- return -1;
- }
- if(avcodec_open2(sndCodecCtx, sndCodec, NULL) < 0)
- return -1;
-
- wanted_spec.freq = sndCodecCtx->sample_rate;
- wanted_spec.format = AUDIO_S16SYS;
- wanted_spec.channels = sndCodecCtx->channels;
- wanted_spec.silence = 0;
- wanted_spec.samples = 2048;
- wanted_spec.callback = audio_callback;
- wanted_spec.userdata = sndCodecCtx;
- if(SDL_OpenAudio(&wanted_spec, &spec) < 0)
- {
- dbmsg("SDL_OpenAudio:%s", SDL_GetError());
- return -1;
- }
- dbmsg("freq=%d, channels=%d, samples=%d", spec.freq, spec.channels, spec.samples);
- packet_queue_init(&audioq);
- SDL_PauseAudio(0);
- }
- //sdl get signal quit
- affmutex = SDL_CreateMutex();
- sdl_thread = SDL_CreateThread(eventThread, NULL);
- rect.x = 0;
- rect.y = 0;
- rect.w = pCodecCtx->width;
- rect.h = pCodecCtx->height;
- packet = (AVPacket*)av_malloc(sizeof(AVPacket));
- if(videoindex != -1)
- {
- img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
- // img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUYV422, SWS_BICUBIC, NULL, NULL, NULL);
- if(img_convert_ctx == NULL)
- {
- dbmsg("img_convert error");
- return -1;
- }
- }
- while( (av_read_frame(pFormatCtx, packet)>=0) && (signal_quit))
- {
- if(packet->stream_index == videoindex)
- {
- dbmsg();
- if((ret=avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, packet)) < 0)
- {
- dbmsg("decocode video error");
- return -1;
- }
- if(frameFinished)
- {
- SDL_LockYUVOverlay(overlay);
- pFrameYUV->data[0] = overlay->pixels[0];
- pFrameYUV->data[1] = overlay->pixels[2];
- pFrameYUV->data[2] = overlay->pixels[1];
- pFrameYUV->linesize[0] = overlay->pitches[0];
- pFrameYUV->linesize[1] = overlay->pitches[2];
- pFrameYUV->linesize[2] = overlay->pitches[1];
- sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0,
- pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);
- SDL_UnlockYUVOverlay(overlay);
- SDL_DisplayYUVOverlay(overlay, &rect);
- SDL_Delay(40);
- }
- }
- if(packet->stream_index == sndindex)
- {
- packet_queue_put(&audioq, packet);
- }
- }
- SDL_WaitThread(sdl_thread, &ret);
- SDL_DestroyMutex(affmutex);
- av_free_packet(packet);
- av_free(pFrameYUV);
- av_free(pFrame);
- avcodec_close(pCodecCtx);
- avcodec_close(sndCodecCtx);
- avformat_close_input(&pFormatCtx);
- return 0;
- }
- cong@msi:/work/ffmpeg/test/3sound_1$
3sound_1.rar (下载后改名为3sound_1.tar.gz)
三.代码
3.1 再次改进
上面的代码太乱了,有很多的全局变量,下面整理一下,学习ffplay做成一个结构体
附录:1.测试的文件格式说明
- test.rmvb-->
- Stream 0
- Type: Audio
- Codec: Cook Auidio(cook)
- Channels: Stereo
- Sample rate: 44100HZ
- Bits per sample: 32
- Stream 1
- Type: Video
- Codec: RealVideo 9/10(4.0)(RV40)
- Resolution: 1024*576
- Decoded format: Planar 4:2:0 YUV
- test.wmv -->
- Stream 0
- Type: Video
- Codec: Windows Media Video 9 (WMV3)
- Language: Chinese
- Resolution: 620x466
- Frame rate: 5
- Decoded format: Planar 4:2:0 YUV
- Stream 1
- Type: Audio
- Codec: Windows Media Audio 2 (WMA2)
- Language: Chinese
- Channels: Mono
- Sample rate: 22050 Hz
- Bits per sample: 32
- test.mp3 -->
- Type: Audio
- Codec: MPEG Audio layer 1/2/3 (mpga)
- Channels: Stereo
- Sample rate: 44100 Hz
- Bitrate: 192 kb/s
- test.wav -->
- Type: Audio
- Codec: PCM S16 LE (s16l)
- Channels: Stereo
- Sample rate: 44100 Hz
- Bits per sample: 16
0 0
- ffmpeg学习---4.Playing Sound
- ffmpeg学习---9.3Playing Sound(更新版)
- FFmpeg和SDL教程之三(Playing Sound)
- Tutorial 03: Playing Sound
- Tutorial 03: Playing Sound
- Playing a sound with AVAudioPlayer播放本地文件
- Playing and Stopping Sound Effect in Cocos2d
- Playing a wave sound from a resource file
- Sound
- Java Sound API 学习笔记
- Java Sound API 学习笔记
- Java Sound API 学习笔记
- Java Sound API 学习笔记[转载]
- FFMPEG学习【ffmpeg工具】
- ffmpeg学习
- 学习ffmpeg
- FFMPEG学习
- FFMPEG学习
- HDU 2296
- hibernate中使用sql
- Android 解决滑动冲突 疑问和解答
- javascript 预处理
- strtok、strtok_s、strtok_r 字符串分割函数
- ffmpeg学习---4.Playing Sound
- 建议29:区别LINQ查询中的IEnumerable<T>和IQueryable<T>
- 对于grub2引导的非debian系linux更新系统内核的脚本
- 简单的委托使用
- 推荐的自动标注工具
- UVA 1386 cellular automaton [循环矩阵+矩阵快速幂]【数学】
- ffmpeg学习---5.Spawning Threads
- Spark笔记
- Linux命令---文件链接