更新版:基于ffmpeg-2.7.2
1.播放声音的代码
代码改进了一下,去掉了很多全局变量
1.1 代码
-
cong@msi:/work/ffmpeg/test/4sound$ 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
-
-
typedef struct PacketQueue
-
{
-
AVPacketList * first_pkt, *last_pkt;
-
int nb_packets;
-
int size;
-
SDL_mutex *mutex;
-
SDL_cond * cond;
-
}PacketQueue;
-
-
static int signal_quit = 0;
-
SDL_mutex *affmutex;
-
SDL_Event sdlevent;
-
SDL_Thread* sdl_thread;
-
-
typedef struct VideoState {
-
int videoindex;
-
int sndindex;
-
int frameFinished;
-
int wanted_freq;
-
int wanted_samples;
-
int wanted_channels;
-
AVFormatContext* pFormatCtx;
-
AVCodecContext* vdoCodecCtx;
-
AVCodecContext* sndCodecCtx;
-
AVCodec* vdoCodec;
-
AVCodec* sndCodec;
-
AVFrame* pFrame;
-
AVFrame* pFrameYUV;
-
AVPacket* packet;
-
struct SwsContext *img_convert_ctx;
-
struct SwrContext *swr_ctx;
-
SDL_Surface* psscreen;
-
SDL_Overlay* overlay;
-
SDL_Rect rect;
-
-
enum AVSampleFormat wanted_fmt;
-
int64_t wanted_channel_layout;
-
PacketQueue audioq;
-
DECLARE_ALIGNED(16,uint8_t,audio_buf2) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 4];
-
}VideoState;
-
-
static int sdl_event_thread(void* data)
-
{
-
while( (0==signal_quit))
-
{
-
SDL_LockMutex(affmutex);
-
while(SDL_PollEvent(&sdlevent))
-
{
-
switch(sdlevent.type)
-
{
-
case SDL_QUIT:
-
{
-
dbmsg("next change signal_quit to 1");
-
signal_quit = 1;
-
}
-
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(;;)
-
{
-
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(VideoState* is)
-
{
-
int i;
-
int len1,len2, data_size, got_frame;
-
int new_packet;
-
int64_t dec_channel_layout;
-
uint8_t *out[] = { is->audio_buf2 };
-
AVPacket *pkt = av_mallocz(sizeof(AVPacket));
-
AVPacket *pkt_temp = av_mallocz(sizeof(AVPacket));
-
AVFrame *frame = av_frame_alloc();
-
for(;;)
-
{
-
while(pkt_temp->size>0 || (!pkt_temp->data && new_packet))
-
{
-
if(frame)
-
{
-
dbmsg("av_get default frame");
-
av_frame_unref(frame); //reset frame
-
}
-
new_packet = 0;
-
len1 = avcodec_decode_audio4(is->sndCodecCtx, 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;
-
-
if(got_frame <= 0) /* No data yet, get more frames */
-
continue;
-
data_size = av_samples_get_buffer_size(NULL, is->sndCodecCtx->channels, frame->nb_samples, is->sndCodecCtx->sample_fmt, 1);
-
dec_channel_layout = (frame->channel_layout && frame->channels==av_get_channel_layout_nb_channels(frame->channel_layout))?
-
frame->channel_layout: is->wanted_channel_layout;
-
-
dbmsg("format=%d:%d,layout=%lld:%lld,rate=%d:%d,samples=%d:%d",frame->format,is->wanted_fmt,
-
(long long) dec_channel_layout,(long long)av_get_default_channel_layout(is->wanted_channels),
-
frame->sample_rate,is->wanted_freq,frame->nb_samples,is->wanted_samples );
-
-
dbmsg("wanted_channel_layout=%lld", (long long)is->wanted_channel_layout);
-
dbmsg("wanted_fmt=%d", is->wanted_fmt);
-
dbmsg("spec.freq=%d", is->wanted_freq);
-
//check: format,channel_layout,rate,sample
-
if((NULL==is->swr_ctx) && ( (frame->format!=is->wanted_fmt) || (dec_channel_layout!=av_get_default_channel_layout(is->wanted_channels)) ||
-
(frame->sample_rate!=is->wanted_freq) || (frame->nb_samples!=is->wanted_samples)) )
-
{
-
dbmsg();
-
if(is->swr_ctx != NULL)
-
swr_free(&is->swr_ctx);
-
dbmsg("wanted_channel_layout=%lld, wanted_fmt=%d, wanted_sample=%d, dec_channel_layout=%lld, frame->format=%d, frame->sample_rate=%d",
-
(long long)is->wanted_channel_layout, is->wanted_fmt, is->wanted_samples, (long long)dec_channel_layout, frame->format, frame->sample_rate);
-
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);
-
if(is->swr_ctx == NULL)
-
{
-
dbmsg("swr_ctx == NULL");
-
}
-
swr_init(is->swr_ctx);
-
dbmsg();
-
}
-
if(is->swr_ctx)
-
{
-
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);
-
dbmsg("needed swr_onvert, len2=%d", len2);
-
data_size = len2 * is->wanted_channels * av_get_bytes_per_sample(is->wanted_fmt);
-
}else {
-
memcpy(is->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(1 == signal_quit)
-
return -1;
-
if((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0)
-
{
-
dbmsg("get packet=%d", new_packet);
-
return -1;
-
}
-
-
*pkt_temp = *pkt;
-
}
-
}
-
-
void audio_callback(void *userdata, Uint8 *stream, int len)
-
{
-
int i;
-
VideoState* is = (VideoState*)userdata;
-
int len1, audio_size;
-
-
static unsigned int audio_buf_size = 0;
-
static unsigned int audio_buf_index = 0;
-
-
while(len > 0)
-
{
-
if(audio_buf_index >= audio_buf_size)
-
{
-
audio_size = audio_decode_frame(is); //decode data is store in is->audio_buf2
-
//dbmsg("audio_size=%d", audio_size);
-
if(audio_size < 0)
-
{
-
/* If error, output silence */
-
audio_buf_size = 1024;
-
memset(is->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 *)is->audio_buf2 + audio_buf_index, len1);
-
len -= len1;
-
stream += len1;
-
audio_buf_index += len1;
-
}
-
}
-
-
int init_ffmpeg_and_SDL(VideoState* is, char* video_file)
-
{
-
int i=0;
-
int ret;
-
SDL_AudioSpec wanted_spec, real_spec;
-
is->videoindex = -1;
-
is->sndindex = -1;
-
if(NULL == video_file)
-
{
-
dbmsg("input file is NULL");
-
return -1;
-
}
-
SDL_Init(SDL_INIT_EVERYTHING);
-
avcodec_register_all();
-
avfilter_register_all();
-
av_register_all();
-
-
is->pFormatCtx = avformat_alloc_context();
-
-
if(avformat_open_input(&is->pFormatCtx, video_file, NULL, NULL)!=0)
-
return -1;
-
-
if(avformat_find_stream_info(is->pFormatCtx, NULL)<0)
-
return -1;
-
av_dump_format(is->pFormatCtx,0, 0, 0);
-
-
for(i=0; i<is->pFormatCtx->nb_streams; i++)
-
{
-
if(is->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
-
{
-
is->videoindex= i;
-
}
-
if(is->pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
-
{
-
is->sndindex= i;
-
}
-
}
-
if(is->videoindex== -1)
-
dbmsg("no video stream found!");
-
if(is->sndindex== -1)
-
dbmsg("no sound stream found!");
-
dbmsg("videoindex=%d, sndindex=%d", is->videoindex, is->sndindex);
-
-
if(is->videoindex != -1)
-
{
-
is->vdoCodecCtx = is->pFormatCtx->streams[is->videoindex]->codec;
-
is->vdoCodec = avcodec_find_decoder(is->vdoCodecCtx->codec_id);
-
if(is->vdoCodec == NULL)
-
{
-
dbmsg("Codec not found");
-
return -1;
-
}
-
if(avcodec_open2(is->vdoCodecCtx, is->vdoCodec, NULL) < 0)
-
return -1;
-
is->pFrame = av_frame_alloc(); //avcodec_alloc_frame
-
is->pFrameYUV = av_frame_alloc();
-
is->img_convert_ctx = sws_getContext(is->vdoCodecCtx->width, is->vdoCodecCtx->height, is->vdoCodecCtx->pix_fmt,
-
is->vdoCodecCtx->width, is->vdoCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
-
if(is->img_convert_ctx == NULL)
-
{
-
dbmsg("img_convert error");
-
return -1;
-
}
-
is->psscreen = SDL_SetVideoMode(is->vdoCodecCtx->width, is->vdoCodecCtx->height, 0, SDL_SWSURFACE);
-
SDL_WM_SetCaption( "FFMPEG Window", NULL);
-
is->overlay = SDL_CreateYUVOverlay(is->vdoCodecCtx->width, is->vdoCodecCtx->height, SDL_YV12_OVERLAY, is->psscreen);
-
is->rect.x = 0;
-
is->rect.y = 0;
-
is->rect.w = is->vdoCodecCtx->width;
-
is->rect.h = is->vdoCodecCtx->height;
-
}
-
if(is->sndindex != -1)
-
{
-
is->sndCodecCtx = is->pFormatCtx->streams[is->sndindex]->codec;
-
is->sndCodec = avcodec_find_decoder(is->sndCodecCtx->codec_id);
-
if(is->sndCodec == NULL)
-
{
-
dbmsg("Codec not found");
-
return -1;
-
}
-
if(avcodec_open2(is->sndCodecCtx, is->sndCodec, NULL) < 0)
-
return -1;
-
-
wanted_spec.freq = is->sndCodecCtx->sample_rate;
-
wanted_spec.format = AUDIO_S16SYS;
-
wanted_spec.channels = is->sndCodecCtx->channels;
-
wanted_spec.silence = 0;
-
wanted_spec.samples = 2048;
-
wanted_spec.callback = audio_callback;
-
wanted_spec.userdata = is;
-
if(SDL_OpenAudio(&wanted_spec, &real_spec) < 0)
-
{
-
dbmsg("SDL_OpenAudio:%s", SDL_GetError());
-
return -1;
-
}
-
//store infomation for audio swr_convert
-
is->wanted_fmt = AV_SAMPLE_FMT_S16; //AUDIO_S16SYS;
-
is->wanted_channel_layout = av_get_default_channel_layout(is->sndCodecCtx->channels);
-
is->wanted_freq = real_spec.freq;
-
is->wanted_samples = real_spec.samples;
-
is->wanted_channels = real_spec.channels;
-
dbmsg("freq=%d, channels=%d, samples=%d", is->wanted_freq, is->wanted_channels, is->wanted_samples);
-
packet_queue_init(&is->audioq);
-
SDL_PauseAudio(0);
-
}
-
return 0;
-
}
-
-
int main(int argc, char **argv)
-
{
-
int ret;
-
VideoState* is = (VideoState*) av_mallocz(sizeof(VideoState));
-
if( (ret=init_ffmpeg_and_SDL(is, argv[1])) != 0)
-
{
-
dbmsg("init_ffmpeg_and SDL error");
-
return -1;
-
}
-
//sdl get signal quit
-
affmutex = SDL_CreateMutex();
-
sdl_thread = SDL_CreateThread(sdl_event_thread, NULL);
-
dbmsg("init over");
-
is->packet = (AVPacket*)av_malloc(sizeof(AVPacket));
-
while( (av_read_frame(is->pFormatCtx, is->packet)>=0) && (signal_quit==0))
-
{
-
if(is->packet->stream_index == is->videoindex)
-
{
-
if((ret=avcodec_decode_video2(is->vdoCodecCtx, is->pFrame, &is->frameFinished, is->packet)) < 0)
-
{
-
dbmsg("decocode video error");
-
return -1;
-
}
-
if(is->frameFinished)
-
{
-
SDL_LockYUVOverlay(is->overlay);
-
is->pFrameYUV->data[0] = is->overlay->pixels[0];
-
is->pFrameYUV->data[1] = is->overlay->pixels[2];
-
is->pFrameYUV->data[2] = is->overlay->pixels[1];
-
is->pFrameYUV->linesize[0] = is->overlay->pitches[0];
-
is->pFrameYUV->linesize[1] = is->overlay->pitches[2];
-
is->pFrameYUV->linesize[2] = is->overlay->pitches[1];
-
sws_scale(is->img_convert_ctx, (const uint8_t* const*)is->pFrame->data, is->pFrame->linesize, 0,
-
is->vdoCodecCtx->height, is->pFrameYUV->data, is->pFrameYUV->linesize);
-
SDL_UnlockYUVOverlay(is->overlay);
-
SDL_DisplayYUVOverlay(is->overlay, &is->rect);
-
SDL_Delay(40);
-
}
-
}
-
-
if(is->packet->stream_index == is->sndindex)
-
{
-
//dbmsg("next put audio");
-
packet_queue_put(&is->audioq, is->packet);
-
}
-
}
-
SDL_WaitThread(sdl_thread, &ret);
-
SDL_DestroyMutex(affmutex);
-
av_free_packet(is->packet);
-
av_free(is->pFrameYUV);
-
av_free(is->pFrame);
-
avcodec_close(is->vdoCodecCtx);
-
avcodec_close(is->sndCodecCtx);
-
avformat_close_input(&is->pFormatCtx);
-
return 0;
-
}
-
cong@msi:/work/ffmpeg/test/4sound$
1.2 代码打包
4sound.rar(下载后改名为4sound.tar.gz)
阅读(1528) | 评论(0) | 转发(0) |