Commit 0c809fbb authored by Max Kellermann's avatar Max Kellermann

Merge branch 'v0.19.x'

parents ad80acb2 cafc266e
...@@ -54,6 +54,12 @@ ver 0.20 (not yet released) ...@@ -54,6 +54,12 @@ ver 0.20 (not yet released)
* update * update
- apply .mpdignore matches to subdirectories - apply .mpdignore matches to subdirectories
ver 0.19.18 (not yet released)
* decoder
- ffmpeg: fix crash with older FFmpeg versions (< 3.0)
- ffmpeg: log detailed error message
- ffmpeg: support FFmpeg 3.1
ver 0.19.17 (2016/07/09) ver 0.19.17 (2016/07/09)
* decoder * decoder
- flac: fix assertion failure while seeking - flac: fix assertion failure while seeking
......
...@@ -78,13 +78,53 @@ ffmpeg_init(gcc_unused const ConfigBlock &block) ...@@ -78,13 +78,53 @@ ffmpeg_init(gcc_unused const ConfigBlock &block)
return true; return true;
} }
#if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(57, 5, 0)
gcc_pure
static const AVCodecParameters &
GetCodecParameters(const AVStream &stream)
{
return *stream.codecpar;
}
gcc_pure
static AVSampleFormat
GetSampleFormat(const AVCodecParameters &codec_params)
{
return AVSampleFormat(codec_params.format);
}
#else
gcc_pure
static const AVCodecContext &
GetCodecParameters(const AVStream &stream)
{
return *stream.codec;
}
gcc_pure
static AVSampleFormat
GetSampleFormat(const AVCodecContext &codec_context)
{
return codec_context.sample_fmt;
}
#endif
gcc_pure
static bool
IsAudio(const AVStream &stream)
{
return GetCodecParameters(stream).codec_type == AVMEDIA_TYPE_AUDIO;
}
gcc_pure gcc_pure
static int static int
ffmpeg_find_audio_stream(const AVFormatContext &format_context) ffmpeg_find_audio_stream(const AVFormatContext &format_context)
{ {
for (unsigned i = 0; i < format_context.nb_streams; ++i) for (unsigned i = 0; i < format_context.nb_streams; ++i)
if (format_context.streams[i]->codec->codec_type == if (IsAudio(*format_context.streams[i]))
AVMEDIA_TYPE_AUDIO)
return i; return i;
return -1; return -1;
...@@ -176,6 +216,43 @@ PtsToPcmFrame(uint64_t pts, const AVStream &stream, ...@@ -176,6 +216,43 @@ PtsToPcmFrame(uint64_t pts, const AVStream &stream,
} }
/** /**
* Invoke decoder_data() with the contents of an #AVFrame.
*/
static DecoderCommand
FfmpegSendFrame(Decoder &decoder, InputStream &is,
AVCodecContext &codec_context,
const AVFrame &frame,
size_t &skip_bytes,
FfmpegBuffer &buffer)
{
Error error;
auto output_buffer =
copy_interleave_frame(codec_context, frame,
buffer, error);
if (output_buffer.IsNull()) {
/* this must be a serious error, e.g. OOM */
LogError(error);
return DecoderCommand::STOP;
}
if (skip_bytes > 0) {
if (skip_bytes >= output_buffer.size) {
skip_bytes -= output_buffer.size;
return DecoderCommand::NONE;
}
output_buffer.data =
(const uint8_t *)output_buffer.data + skip_bytes;
output_buffer.size -= skip_bytes;
skip_bytes = 0;
}
return decoder_data(decoder, is,
output_buffer.data, output_buffer.size,
codec_context.bit_rate / 1000);
}
/**
* Decode an #AVPacket and send the resulting PCM data to the decoder * Decode an #AVPacket and send the resulting PCM data to the decoder
* API. * API.
* *
...@@ -207,8 +284,6 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is, ...@@ -207,8 +284,6 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
stream.time_base)); stream.time_base));
} }
Error error;
DecoderCommand cmd = DecoderCommand::NONE; DecoderCommand cmd = DecoderCommand::NONE;
while (packet.size > 0 && cmd == DecoderCommand::NONE) { while (packet.size > 0 && cmd == DecoderCommand::NONE) {
int got_frame = 0; int got_frame = 0;
...@@ -227,35 +302,32 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is, ...@@ -227,35 +302,32 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
if (!got_frame || frame.nb_samples <= 0) if (!got_frame || frame.nb_samples <= 0)
continue; continue;
auto output_buffer = cmd = FfmpegSendFrame(decoder, is, codec_context,
copy_interleave_frame(codec_context, frame, frame, skip_bytes,
buffer, error); buffer);
if (output_buffer.IsNull()) {
/* this must be a serious error,
e.g. OOM */
LogError(error);
return DecoderCommand::STOP;
}
if (skip_bytes > 0) {
if (skip_bytes >= output_buffer.size) {
skip_bytes -= output_buffer.size;
continue;
}
output_buffer.data =
(const uint8_t *)output_buffer.data + skip_bytes;
output_buffer.size -= skip_bytes;
skip_bytes = 0;
}
cmd = decoder_data(decoder, is,
output_buffer.data, output_buffer.size,
codec_context.bit_rate / 1000);
} }
return cmd; return cmd;
} }
static DecoderCommand
ffmpeg_send_packet(Decoder &decoder, InputStream &is,
const AVPacket &packet,
AVCodecContext &codec_context,
const AVStream &stream,
AVFrame &frame,
uint64_t min_frame, size_t pcm_frame_size,
FfmpegBuffer &buffer)
{
return ffmpeg_send_packet(decoder, is,
/* copy the AVPacket, because FFmpeg
< 3.0 requires this */
AVPacket(packet),
codec_context, stream,
frame, min_frame, pcm_frame_size,
buffer);
}
gcc_const gcc_const
static SampleFormat static SampleFormat
ffmpeg_sample_format(enum AVSampleFormat sample_fmt) ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
...@@ -457,21 +529,22 @@ FfmpegDecode(Decoder &decoder, InputStream &input, ...@@ -457,21 +529,22 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
AVStream &av_stream = *format_context.streams[audio_stream]; AVStream &av_stream = *format_context.streams[audio_stream];
AVCodecContext &codec_context = *av_stream.codec; AVCodecContext *codec_context = av_stream.codec;
const auto &codec_params = GetCodecParameters(av_stream);
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 25, 0) #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54, 25, 0)
const AVCodecDescriptor *codec_descriptor = const AVCodecDescriptor *codec_descriptor =
avcodec_descriptor_get(codec_context.codec_id); avcodec_descriptor_get(codec_params.codec_id);
if (codec_descriptor != nullptr) if (codec_descriptor != nullptr)
FormatDebug(ffmpeg_domain, "codec '%s'", FormatDebug(ffmpeg_domain, "codec '%s'",
codec_descriptor->name); codec_descriptor->name);
#else #else
if (codec_context.codec_name[0] != 0) if (codec_context->codec_name[0] != 0)
FormatDebug(ffmpeg_domain, "codec '%s'", FormatDebug(ffmpeg_domain, "codec '%s'",
codec_context.codec_name); codec_context->codec_name);
#endif #endif
AVCodec *codec = avcodec_find_decoder(codec_context.codec_id); AVCodec *codec = avcodec_find_decoder(codec_params.codec_id);
if (!codec) { if (!codec) {
LogError(ffmpeg_domain, "Unsupported audio codec"); LogError(ffmpeg_domain, "Unsupported audio codec");
...@@ -479,7 +552,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input, ...@@ -479,7 +552,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
} }
const SampleFormat sample_format = const SampleFormat sample_format =
ffmpeg_sample_format(codec_context.sample_fmt); ffmpeg_sample_format(GetSampleFormat(codec_params));
if (sample_format == SampleFormat::UNDEFINED) { if (sample_format == SampleFormat::UNDEFINED) {
// (error message already done by ffmpeg_sample_format()) // (error message already done by ffmpeg_sample_format())
return; return;
...@@ -488,9 +561,9 @@ FfmpegDecode(Decoder &decoder, InputStream &input, ...@@ -488,9 +561,9 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
Error error; Error error;
AudioFormat audio_format; AudioFormat audio_format;
if (!audio_format_init_checked(audio_format, if (!audio_format_init_checked(audio_format,
codec_context.sample_rate, codec_params.sample_rate,
sample_format, sample_format,
codec_context.channels, error)) { codec_params.channels, error)) {
LogError(error); LogError(error);
return; return;
} }
...@@ -500,7 +573,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input, ...@@ -500,7 +573,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
values into AVCodecContext.channels - a change that will be values into AVCodecContext.channels - a change that will be
reverted later by avcodec_decode_audio3() */ reverted later by avcodec_decode_audio3() */
const int open_result = avcodec_open2(&codec_context, codec, nullptr); const int open_result = avcodec_open2(codec_context, codec, nullptr);
if (open_result < 0) { if (open_result < 0) {
LogError(ffmpeg_domain, "Could not open codec"); LogError(ffmpeg_domain, "Could not open codec");
return; return;
...@@ -543,7 +616,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input, ...@@ -543,7 +616,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0) AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0)
decoder_seek_error(decoder); decoder_seek_error(decoder);
else { else {
avcodec_flush_buffers(&codec_context); avcodec_flush_buffers(codec_context);
min_frame = decoder_seek_where_frame(decoder); min_frame = decoder_seek_where_frame(decoder);
decoder_command_finished(decoder); decoder_command_finished(decoder);
} }
...@@ -560,8 +633,8 @@ FfmpegDecode(Decoder &decoder, InputStream &input, ...@@ -560,8 +633,8 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
if (packet.stream_index == audio_stream) { if (packet.stream_index == audio_stream) {
cmd = ffmpeg_send_packet(decoder, input, cmd = ffmpeg_send_packet(decoder, input,
std::move(packet), packet,
codec_context, *codec_context,
av_stream, av_stream,
*frame, *frame,
min_frame, audio_format.GetFrameSize(), min_frame, audio_format.GetFrameSize(),
...@@ -585,7 +658,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input, ...@@ -585,7 +658,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
av_free(frame); av_free(frame);
#endif #endif
avcodec_close(&codec_context); avcodec_close(codec_context);
} }
static void static void
...@@ -612,6 +685,7 @@ ffmpeg_decode(Decoder &decoder, InputStream &input) ...@@ -612,6 +685,7 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
} }
FfmpegDecode(decoder, input, *format_context); FfmpegDecode(decoder, input, *format_context);
avformat_close_input(&format_context); avformat_close_input(&format_context);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment