mirror of
https://github.com/tuxbox-neutrino/neutrino.git
synced 2025-08-27 23:42:58 +02:00
driver/audiodec/ffmpegdec.cpp: add support to downmix and play multichannel audio,
fix seek function, use duration reported by ffmpeg if reported, set analyzeduration to 1 second
This commit is contained in:
@@ -49,6 +49,8 @@ extern "C" {
|
|||||||
|
|
||||||
extern cAudio * audioDecoder;
|
extern cAudio * audioDecoder;
|
||||||
|
|
||||||
|
//#define FFDEC_DEBUG
|
||||||
|
|
||||||
#define ProgName "FfmpegDec"
|
#define ProgName "FfmpegDec"
|
||||||
|
|
||||||
#define COVERDIR "/tmp/cover"
|
#define COVERDIR "/tmp/cover"
|
||||||
@@ -64,7 +66,7 @@ static void log_callback(void *, int, const char *format, va_list ap)
|
|||||||
|
|
||||||
CFfmpegDec::CFfmpegDec(void)
|
CFfmpegDec::CFfmpegDec(void)
|
||||||
{
|
{
|
||||||
av_log_set_callback(log_callback);
|
//av_log_set_callback(log_callback);
|
||||||
meta_data_valid = false;
|
meta_data_valid = false;
|
||||||
buffer_size = 0x1000;
|
buffer_size = 0x1000;
|
||||||
buffer = NULL;
|
buffer = NULL;
|
||||||
@@ -90,6 +92,9 @@ static int read_packet(void *opaque, uint8_t *buf, int buf_size)
|
|||||||
|
|
||||||
int64_t CFfmpegDec::Seek(int64_t offset, int whence)
|
int64_t CFfmpegDec::Seek(int64_t offset, int whence)
|
||||||
{
|
{
|
||||||
|
if (whence == AVSEEK_SIZE)
|
||||||
|
return (int64_t) -1;
|
||||||
|
|
||||||
fseek((FILE *) in, (long) offset, whence);
|
fseek((FILE *) in, (long) offset, whence);
|
||||||
return (int64_t) ftell((FILE *) in);
|
return (int64_t) ftell((FILE *) in);
|
||||||
}
|
}
|
||||||
@@ -109,9 +114,10 @@ bool CFfmpegDec::Init(void *_in, const CFile::FileType ft)
|
|||||||
type_info = "";
|
type_info = "";
|
||||||
total_time = 0;
|
total_time = 0;
|
||||||
bitrate = 0;
|
bitrate = 0;
|
||||||
total_time = 0;
|
|
||||||
|
|
||||||
|
#ifdef FFDEC_DEBUG
|
||||||
av_log_set_level(AV_LOG_DEBUG);
|
av_log_set_level(AV_LOG_DEBUG);
|
||||||
|
#endif
|
||||||
|
|
||||||
AVIOContext *avioc = NULL;
|
AVIOContext *avioc = NULL;
|
||||||
in = _in;
|
in = _in;
|
||||||
@@ -128,6 +134,8 @@ bool CFfmpegDec::Init(void *_in, const CFile::FileType ft)
|
|||||||
if (is_stream)
|
if (is_stream)
|
||||||
avc->probesize = 128 * 1024;
|
avc->probesize = 128 * 1024;
|
||||||
|
|
||||||
|
av_opt_set_int(avc, "analyzeduration", 1000000, 0);
|
||||||
|
|
||||||
avioc = avio_alloc_context (buffer, buffer_size, 0, this, read_packet, NULL, seek_packet);
|
avioc = avio_alloc_context (buffer, buffer_size, 0, this, read_packet, NULL, seek_packet);
|
||||||
if (!avioc) {
|
if (!avioc) {
|
||||||
av_freep(&buffer);
|
av_freep(&buffer);
|
||||||
@@ -152,6 +160,9 @@ bool CFfmpegDec::Init(void *_in, const CFile::FileType ft)
|
|||||||
case CFile::FILE_FLAC:
|
case CFile::FILE_FLAC:
|
||||||
input_format = av_find_input_format("flac");
|
input_format = av_find_input_format("flac");
|
||||||
break;
|
break;
|
||||||
|
case CFile::FILE_AAC:
|
||||||
|
input_format = av_find_input_format("aac");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -222,6 +233,7 @@ CBaseDec::RetCode CFfmpegDec::Decoder(FILE *_in, const CFile::FileType ft, int /
|
|||||||
}
|
}
|
||||||
|
|
||||||
mSampleRate = samplerate;
|
mSampleRate = samplerate;
|
||||||
|
mChannels = av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO);
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
audioDecoder->PrepareClipPlay(mChannels, mSampleRate, 16, 1);
|
audioDecoder->PrepareClipPlay(mChannels, mSampleRate, 16, 1);
|
||||||
#else
|
#else
|
||||||
@@ -233,7 +245,8 @@ CBaseDec::RetCode CFfmpegDec::Decoder(FILE *_in, const CFile::FileType ft, int /
|
|||||||
av_init_packet(&rpacket);
|
av_init_packet(&rpacket);
|
||||||
|
|
||||||
av_opt_set_int(swr, "in_channel_layout", c->channel_layout, 0);
|
av_opt_set_int(swr, "in_channel_layout", c->channel_layout, 0);
|
||||||
av_opt_set_int(swr, "out_channel_layout", c->channel_layout, 0);
|
//av_opt_set_int(swr, "out_channel_layout", c->channel_layout, 0);
|
||||||
|
av_opt_set_int(swr, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0);
|
||||||
av_opt_set_int(swr, "in_sample_rate", c->sample_rate, 0);
|
av_opt_set_int(swr, "in_sample_rate", c->sample_rate, 0);
|
||||||
av_opt_set_int(swr, "out_sample_rate", c->sample_rate, 0);
|
av_opt_set_int(swr, "out_sample_rate", c->sample_rate, 0);
|
||||||
av_opt_set_int(swr, "in_sample_fmt", c->sample_fmt, 0);
|
av_opt_set_int(swr, "in_sample_fmt", c->sample_fmt, 0);
|
||||||
@@ -315,7 +328,7 @@ CBaseDec::RetCode CFfmpegDec::Decoder(FILE *_in, const CFile::FileType ft, int /
|
|||||||
c->sample_rate, c->sample_rate, AV_ROUND_UP);
|
c->sample_rate, c->sample_rate, AV_ROUND_UP);
|
||||||
if (outsamples > outsamples_max) {
|
if (outsamples > outsamples_max) {
|
||||||
av_free(outbuf);
|
av_free(outbuf);
|
||||||
if (av_samples_alloc(&outbuf, &out_samples, c->channels,
|
if (av_samples_alloc(&outbuf, &out_samples, mChannels, //c->channels,
|
||||||
frame->nb_samples, AV_SAMPLE_FMT_S16, 1) < 0) {
|
frame->nb_samples, AV_SAMPLE_FMT_S16, 1) < 0) {
|
||||||
Status=WRITE_ERR;
|
Status=WRITE_ERR;
|
||||||
packet.size = 0;
|
packet.size = 0;
|
||||||
@@ -325,7 +338,7 @@ CBaseDec::RetCode CFfmpegDec::Decoder(FILE *_in, const CFile::FileType ft, int /
|
|||||||
}
|
}
|
||||||
outsamples = swr_convert(swr, &outbuf, outsamples,
|
outsamples = swr_convert(swr, &outbuf, outsamples,
|
||||||
(const uint8_t **) &frame->data[0], frame->nb_samples);
|
(const uint8_t **) &frame->data[0], frame->nb_samples);
|
||||||
int outbuf_size = av_samples_get_buffer_size(&out_samples, c->channels,
|
int outbuf_size = av_samples_get_buffer_size(&out_samples, mChannels, //c->channels,
|
||||||
outsamples, AV_SAMPLE_FMT_S16, 1);
|
outsamples, AV_SAMPLE_FMT_S16, 1);
|
||||||
|
|
||||||
if(audioDecoder->WriteClip((unsigned char*) outbuf, outbuf_size) != outbuf_size)
|
if(audioDecoder->WriteClip((unsigned char*) outbuf, outbuf_size) != outbuf_size)
|
||||||
@@ -403,7 +416,9 @@ bool CFfmpegDec::SetMetaData(FILE *_in, CFile::FileType ft, CAudioMetaData* m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//fseek((FILE *) in, 0, SEEK_SET);
|
//fseek((FILE *) in, 0, SEEK_SET);
|
||||||
|
#ifdef FFDEC_DEBUG
|
||||||
av_dump_format(avc, 0, "", 0);
|
av_dump_format(avc, 0, "", 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
codec = NULL;
|
codec = NULL;
|
||||||
best_stream = av_find_best_stream(avc, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
|
best_stream = av_find_best_stream(avc, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
|
||||||
@@ -431,6 +446,11 @@ bool CFfmpegDec::SetMetaData(FILE *_in, CFile::FileType ft, CAudioMetaData* m)
|
|||||||
|
|
||||||
bitrate = 0;
|
bitrate = 0;
|
||||||
total_time = 0;
|
total_time = 0;
|
||||||
|
|
||||||
|
if (avc->duration != int64_t(AV_NOPTS_VALUE))
|
||||||
|
total_time = avc->duration / int64_t(AV_TIME_BASE);
|
||||||
|
printf("CFfmpegDec: format %s (%s) duration %ld\n", avc->iformat->name, type_info.c_str(), total_time);
|
||||||
|
|
||||||
for(unsigned int i = 0; i < avc->nb_streams; i++) {
|
for(unsigned int i = 0; i < avc->nb_streams; i++) {
|
||||||
if (avc->streams[i]->codec->bit_rate > 0)
|
if (avc->streams[i]->codec->bit_rate > 0)
|
||||||
bitrate += avc->streams[i]->codec->bit_rate;
|
bitrate += avc->streams[i]->codec->bit_rate;
|
||||||
@@ -448,7 +468,7 @@ bool CFfmpegDec::SetMetaData(FILE *_in, CFile::FileType ft, CAudioMetaData* m)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(m->filesize && bitrate)
|
if(!total_time && m->filesize && bitrate)
|
||||||
total_time = 8 * m->filesize / bitrate;
|
total_time = 8 * m->filesize / bitrate;
|
||||||
|
|
||||||
meta_data_valid = true;
|
meta_data_valid = true;
|
||||||
|
Reference in New Issue
Block a user