blob: 312d5ddbdf258e25deac95c33d72f4d67e42c30e [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/logging.h"
#include "services/media/framework_ffmpeg/ffmpeg_video_decoder.h"
namespace mojo {
namespace media {
FfmpegVideoDecoder::FfmpegVideoDecoder(AvCodecContextPtr av_codec_context)
: FfmpegDecoderBase(std::move(av_codec_context)) {
DCHECK(context());
}
FfmpegVideoDecoder::~FfmpegVideoDecoder() {}
int FfmpegVideoDecoder::Decode(const AVPacket& av_packet,
const ffmpeg::AvFramePtr& av_frame_ptr,
PayloadAllocator* allocator,
bool* frame_decoded_out) {
DCHECK(av_frame_ptr);
DCHECK(allocator);
DCHECK(frame_decoded_out);
DCHECK(context());
int frame_decoded = 0;
int input_bytes_used = avcodec_decode_video2(
context().get(), av_frame_ptr.get(), &frame_decoded, &av_packet);
*frame_decoded_out = frame_decoded != 0;
return input_bytes_used;
}
PacketPtr FfmpegVideoDecoder::CreateOutputPacket(const AVFrame& av_frame,
PayloadAllocator* allocator) {
DCHECK(allocator);
// End of stream is indicated when we're draining and produce no packet.
// TODO(dalesat): This is just a copy of the audio version.
return Packet::Create(av_frame.pts, false, packet_size_, av_frame.data[0],
allocator);
}
PacketPtr FfmpegVideoDecoder::CreateOutputEndOfStreamPacket() {
// TODO(dalesat): Presentation time for this packet.
return Packet::CreateEndOfStream(0);
}
int FfmpegVideoDecoder::AllocateBufferForAvFrame(
AVCodecContext* av_codec_context,
AVFrame* av_frame,
int flags) {
// It's important to use av_codec_context here rather than context(),
// because av_codec_context is different for different threads when we're
// decoding on multiple threads. If this code is moved to an instance method,
// be sure to avoid using context().
// TODO(dalesat): Not sure why/if this is needed.
// int result = av_image_check_size(
// av_codec_context->width,
// av_codec_context->height,
// 0,
// NULL);
// if (result < 0) {
// DCHECK(false) << "av_image_check_size failed";
// return result;
//}
// TODO(dalesat): Not sure why this is needed.
int coded_width =
std::max(av_codec_context->width, av_codec_context->coded_width);
int coded_height =
std::max(av_codec_context->height, av_codec_context->coded_height);
DCHECK_EQ(coded_width, av_codec_context->coded_width)
<< "coded width is less than width";
DCHECK_EQ(coded_height, av_codec_context->coded_height)
<< "coded height is less than height";
// TODO(dalesat): Fill in av_frame->data and av_frame->data for each plane.
av_frame->width = coded_width;
av_frame->height = coded_height;
av_frame->format = av_codec_context->pix_fmt;
av_frame->reordered_opaque = av_codec_context->reordered_opaque;
av_frame->buf[0] = av_buffer_create(
av_frame->data[0], // Because this is the first chunk in the buffer.
0, // TODO(dalesat): Provide this.
ReleaseBufferForAvFrame,
nullptr, // opaque
0); // flags
return 0;
}
void FfmpegVideoDecoder::ReleaseBufferForAvFrame(void* opaque,
uint8_t* buffer) {
// Nothing to do.
// TODO(dalesat): Can we get rid of this method altogether?
}
} // namespace media
} // namespace mojo