Index: services/media/framework_ffmpeg/ffmpeg_video_decoder.cc |
diff --git a/services/media/framework_ffmpeg/ffmpeg_video_decoder.cc b/services/media/framework_ffmpeg/ffmpeg_video_decoder.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b7a7676a45dfd45cb43c97791770d0780ef60e6f |
--- /dev/null |
+++ b/services/media/framework_ffmpeg/ffmpeg_video_decoder.cc |
@@ -0,0 +1,110 @@ |
+// 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( |
+ PayloadAllocator* allocator, |
+ bool* frame_decoded_out) { |
+ DCHECK(allocator); |
+ DCHECK(frame_decoded_out); |
+ DCHECK(context()); |
+ DCHECK(frame()); |
+ |
+ int frame_decoded = 0; |
+ int input_bytes_used = avcodec_decode_video2( |
+ context().get(), |
+ frame().get(), |
+ &frame_decoded, |
+ &packet()); |
+ *frame_decoded_out = frame_decoded != 0; |
+ return input_bytes_used; |
+} |
+ |
+PacketPtr FfmpegVideoDecoder::CreateOutputPacket(PayloadAllocator* allocator) { |
+ DCHECK(allocator); |
+ DCHECK(frame()); |
+ |
+ // 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( |
+ frame()->pts, |
+ frame()->pkt_duration, |
+ false, |
+ packet_size_, |
+ 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 |