一.最原始版的
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;
-
}
1.2 Makefile
-
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
测试时发现只有wav格式的播放没有问题,
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$
2.3 代码打包
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
阅读(4290) | 评论(3) | 转发(0) |