Merge branch 'v0.19.x'

This commit is contained in:
Max Kellermann 2016-07-29 09:00:20 +02:00
commit 0c809fbb40
2 changed files with 122 additions and 42 deletions

6
NEWS
View File

@ -54,6 +54,12 @@ ver 0.20 (not yet released)
* update
- 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)
* decoder
- flac: fix assertion failure while seeking

View File

@ -78,13 +78,53 @@ ffmpeg_init(gcc_unused const ConfigBlock &block)
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
static int
ffmpeg_find_audio_stream(const AVFormatContext &format_context)
{
for (unsigned i = 0; i < format_context.nb_streams; ++i)
if (format_context.streams[i]->codec->codec_type ==
AVMEDIA_TYPE_AUDIO)
if (IsAudio(*format_context.streams[i]))
return i;
return -1;
@ -175,6 +215,43 @@ PtsToPcmFrame(uint64_t pts, const AVStream &stream,
return av_rescale_q(pts, stream.time_base, codec_context.time_base);
}
/**
* 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
* API.
@ -207,8 +284,6 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
stream.time_base));
}
Error error;
DecoderCommand cmd = DecoderCommand::NONE;
while (packet.size > 0 && cmd == DecoderCommand::NONE) {
int got_frame = 0;
@ -227,35 +302,32 @@ ffmpeg_send_packet(Decoder &decoder, InputStream &is,
if (!got_frame || frame.nb_samples <= 0)
continue;
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;
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);
cmd = FfmpegSendFrame(decoder, is, codec_context,
frame, skip_bytes,
buffer);
}
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
static SampleFormat
ffmpeg_sample_format(enum AVSampleFormat sample_fmt)
@ -457,21 +529,22 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
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)
const AVCodecDescriptor *codec_descriptor =
avcodec_descriptor_get(codec_context.codec_id);
avcodec_descriptor_get(codec_params.codec_id);
if (codec_descriptor != nullptr)
FormatDebug(ffmpeg_domain, "codec '%s'",
codec_descriptor->name);
#else
if (codec_context.codec_name[0] != 0)
if (codec_context->codec_name[0] != 0)
FormatDebug(ffmpeg_domain, "codec '%s'",
codec_context.codec_name);
codec_context->codec_name);
#endif
AVCodec *codec = avcodec_find_decoder(codec_context.codec_id);
AVCodec *codec = avcodec_find_decoder(codec_params.codec_id);
if (!codec) {
LogError(ffmpeg_domain, "Unsupported audio codec");
@ -479,7 +552,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
}
const SampleFormat sample_format =
ffmpeg_sample_format(codec_context.sample_fmt);
ffmpeg_sample_format(GetSampleFormat(codec_params));
if (sample_format == SampleFormat::UNDEFINED) {
// (error message already done by ffmpeg_sample_format())
return;
@ -488,9 +561,9 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
Error error;
AudioFormat audio_format;
if (!audio_format_init_checked(audio_format,
codec_context.sample_rate,
codec_params.sample_rate,
sample_format,
codec_context.channels, error)) {
codec_params.channels, error)) {
LogError(error);
return;
}
@ -500,7 +573,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
values into AVCodecContext.channels - a change that will be
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) {
LogError(ffmpeg_domain, "Could not open codec");
return;
@ -543,7 +616,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
AVSEEK_FLAG_ANY|AVSEEK_FLAG_BACKWARD) < 0)
decoder_seek_error(decoder);
else {
avcodec_flush_buffers(&codec_context);
avcodec_flush_buffers(codec_context);
min_frame = decoder_seek_where_frame(decoder);
decoder_command_finished(decoder);
}
@ -560,8 +633,8 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
if (packet.stream_index == audio_stream) {
cmd = ffmpeg_send_packet(decoder, input,
std::move(packet),
codec_context,
packet,
*codec_context,
av_stream,
*frame,
min_frame, audio_format.GetFrameSize(),
@ -585,7 +658,7 @@ FfmpegDecode(Decoder &decoder, InputStream &input,
av_free(frame);
#endif
avcodec_close(&codec_context);
avcodec_close(codec_context);
}
static void
@ -612,6 +685,7 @@ ffmpeg_decode(Decoder &decoder, InputStream &input)
}
FfmpegDecode(decoder, input, *format_context);
avformat_close_input(&format_context);
}