FFmpeg音频解码流程
Skip to content
Product
Team
Enterprise
Explore
Marketplace
Pricing
Sign in
Sign up
brookicv /
FFMPEG-study
Public
Code
Issues 1
Pull requests 1
Actions
Projects
Wiki
Security
Insights
FFMPEG-study/FFmpeg2.cpp
@brookicv
brookicv 完善播放音频的代码,解决播放杂音问题
Latest commit 17b45b4 on 10 Aug 2016
History
1 contributor
357 lines (281 sloc) 7.86 KB
# include <iostream>
# include <stdio.h>
# include <assert.h>
# include <SDL.h>
# include <SDL_thread.h>
extern "C"
{
# include <libavcodec\avcodec.h>
# include <libavformat\avformat.h>
# include <libswscale\swscale.h>
# include <libswresample\swresample.h>
}
using namespace std;
typedef struct PacketQueue
{
AVPacketList *first_pkt;
AVPacketList *last_pkt;
int nb_packets;
int size;
SDL_mutex* mutext;
SDL_cond* cond;
}PacketQueue;
PacketQueue audioq;
int quit = 0;
AVFrame wanted_frame;
void packet_queue_init(PacketQueue* q)
{
q->last_pkt = nullptr;
q->first_pkt = nullptr;
q->mutext = SDL_CreateMutex();
q->cond = SDL_CreateCond();
}
int packet_queue_put(PacketQueue*q, AVPacket *pkt)
{
AVPacketList *pktl;
if (av_dup_packet(pkt) < 0)
return -1;
pktl = (AVPacketList*)av_malloc(sizeof(AVPacketList));
if (!pktl)
return -1;
pktl->pkt = *pkt;
pktl->next = nullptr;
SDL_LockMutex(q->mutext);
if (!q->last_pkt)
q->first_pkt = pktl;
else
q->last_pkt->next = pktl;
q->last_pkt = pktl;
q->nb_packets++;
q->size += pkt->size;
SDL_CondSignal(q->cond);
SDL_UnlockMutex(q->mutext);
return 0;
}
static int packet_queue_get(PacketQueue* q, AVPacket* pkt, bool block)
{
AVPacketList* pktl;
int ret;
SDL_LockMutex(q->mutext);
while (true)
{
if (quit)
{
ret = -1;
break;
}
pktl = q->first_pkt;
if (pktl)
{
q->first_pkt = pktl->next;
if (!q->first_pkt)
q->last_pkt = nullptr;
q->nb_packets--;
q->size -= pktl->pkt.size;
*pkt = pktl->pkt;
av_free(pktl);
ret = 1;
break;
}
else if (!block)
{
ret = 0;
break;
}
else
{
SDL_CondWait(q->cond, q->mutext);
}
}
SDL_UnlockMutex(q->mutext);
return ret;
}
int audio_decode_frame(AVCodecContext* aCodecCtx, uint8_t* audio_buf, int buf_size)
{
static AVPacket pkt;
static uint8_t* audio_pkt_data = nullptr;
static int audio_pkt_size = 0;
static AVFrame frame;
int len1;
int data_size = 0;
SwrContext* swr_ctx = nullptr;
while (true)
{
while (audio_pkt_size > 0)
{
int got_frame = 0;
len1 = avcodec_decode_audio4(aCodecCtx, &frame, &got_frame, &pkt);
if (len1 < 0)
{
audio_pkt_size = 0;
break;
}
audio_pkt_data += len1;
audio_pkt_size -= len1;
data_size = 0;
if (got_frame)
{
data_size = av_samples_get_buffer_size(nullptr, aCodecCtx->channels, frame.nb_samples, aCodecCtx->sample_fmt, 1);
assert(data_size <= buf_size);
memcpy(audio_buf, frame.data[0], data_size);
}
if (frame.channels > 0 && frame.channel_layout == 0)
frame.channel_layout = av_get_default_channel_layout(frame.channels);
else if (frame.channels == 0 && frame.channel_layout > 0)
frame.channels = av_get_channel_layout_nb_channels(frame.channel_layout);
if (swr_ctx)
{
swr_free(&swr_ctx);
swr_ctx = nullptr;
}
swr_ctx = swr_alloc_set_opts(nullptr, wanted_frame.channel_layout, (AVSampleFormat)wanted_frame.format, wanted_frame.sample_rate,
frame.channel_layout, (AVSampleFormat)frame.format, frame.sample_rate, 0, nullptr);
if (!swr_ctx || swr_init(swr_ctx) < 0)
{
cout << "swr_init failed:" << endl;
break;
}
int dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, frame.sample_rate) + frame.nb_samples,
wanted_frame.sample_rate, wanted_frame.format,AVRounding(1));
int len2 = swr_convert(swr_ctx, &audio_buf, dst_nb_samples,
(const uint8_t**)frame.data, frame.nb_samples);
if (len2 < 0)
{
cout << "swr_convert failed\n";
break;
}
return wanted_frame.channels * len2 * av_get_bytes_per_sample((AVSampleFormat)wanted_frame.format);
if (data_size <= 0)
continue;
return data_size;
}
if (pkt.data)
av_free_packet(&pkt);
if (quit)
return -1;
if (packet_queue_get(&audioq, &pkt, true) < 0)
return -1;
audio_pkt_data = pkt.data;
audio_pkt_size = pkt.size;
}
}
static const int MAX_AUDIO_FRAME_SIZE = 192000;
static const int SDL_AUDIO_BUFFER_SIZE = 1024;
void audio_callback(void* userdata, Uint8* stream, int len)
{
AVCodecContext* aCodecCtx = (AVCodecContext*)userdata;
int len1, audio_size;
static uint8_t audio_buff[(MAX_AUDIO_FRAME_SIZE * 3) / 2];
static unsigned int audio_buf_size = 0;
static unsigned int audio_buf_index = 0;
SDL_memset(stream, 0, len);
while (len > 0)
{
if (audio_buf_index >= audio_buf_size)
{
audio_size = audio_decode_frame(aCodecCtx, audio_buff, sizeof(audio_buff));
if (audio_size < 0)
{
audio_buf_size = 1024;
memset(audio_buff, 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;
SDL_MixAudio(stream, audio_buff + audio_buf_index, len, SDL_MIX_MAXVOLUME);
len -= len1;
stream += len1;
audio_buf_index += len1;
}
}
int main(int argv, char* argc[])
{
av_register_all();
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER);
char* filenName = "F:\\test.rmvb";
AVFormatContext* pFormatCtx = nullptr;
if (avformat_open_input(&pFormatCtx, filenName, nullptr, nullptr) != 0)
return -1;
if (avformat_find_stream_info(pFormatCtx, nullptr) < 0)
return -1;
av_dump_format(pFormatCtx, 0, filenName, 0);
int audioStream = -1;
for (int i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
audioStream = i;
break;
}
}
if (audioStream == -1)
return -1;
AVCodecContext* pCodecCtxOrg = nullptr;
AVCodecContext* pCodecCtx = nullptr;
AVCodec* pCodec = nullptr;
pCodecCtxOrg = pFormatCtx->streams[audioStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtxOrg->codec_id);
if (!pCodec)
{
cout << "Unsupported codec!" << endl;
return -1;
}
pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_copy_context(pCodecCtx, pCodecCtxOrg) != 0)
{
cout << "Could not copy codec context!" << endl;
return -1;
}
SDL_AudioSpec wanted_spec, spec;
wanted_spec.freq = pCodecCtx->sample_rate;
wanted_spec.format = AUDIO_S16SYS;
wanted_spec.channels = pCodecCtx->channels;
wanted_spec.silence = 0;
wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE;
wanted_spec.callback = audio_callback;
wanted_spec.userdata = pCodecCtx;
if (SDL_OpenAudio(&wanted_spec, &spec) < 0)
{
cout << "Open audio failed:" << SDL_GetError() << endl;
getchar();
return -1;
}
wanted_frame.format = AV_SAMPLE_FMT_S16;
wanted_frame.sample_rate = spec.freq;
wanted_frame.channel_layout = av_get_default_channel_layout(spec.channels);
wanted_frame.channels = spec.channels;
avcodec_open2(pCodecCtx, pCodec, nullptr);
packet_queue_init(&audioq);
SDL_PauseAudio(0);
AVPacket packet;
while (av_read_frame(pFormatCtx, &packet) >= 0)
{
if (packet.stream_index == audioStream)
packet_queue_put(&audioq, &packet);
else
av_free_packet(&packet);
}
getchar();
return 0;
}