| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "media/filters/omx_video_decoder.h" | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/callback.h" | |
| 9 #include "base/message_loop.h" | |
| 10 #include "media/base/callback.h" | |
| 11 #include "media/base/filter_host.h" | |
| 12 #include "media/base/limits.h" | |
| 13 #include "media/ffmpeg/ffmpeg_common.h" | |
| 14 #include "media/video/omx_video_decode_engine.h" | |
| 15 | |
| 16 namespace media { | |
| 17 | |
| 18 OmxVideoDecoder::OmxVideoDecoder( | |
| 19 MessageLoop* message_loop, | |
| 20 VideoDecodeContext* context) | |
| 21 : message_loop_(message_loop), | |
| 22 decode_engine_(new OmxVideoDecodeEngine()), | |
| 23 decode_context_(context) { | |
| 24 DCHECK(decode_engine_.get()); | |
| 25 memset(&info_, 0, sizeof(info_)); | |
| 26 } | |
| 27 | |
| 28 OmxVideoDecoder::~OmxVideoDecoder() { | |
| 29 // TODO(hclam): Make sure OmxVideoDecodeEngine is stopped. | |
| 30 } | |
| 31 | |
| 32 void OmxVideoDecoder::Initialize(DemuxerStream* demuxer_stream, | |
| 33 FilterCallback* callback, | |
| 34 StatisticsCallback* stats_callback) { | |
| 35 if (MessageLoop::current() != message_loop_) { | |
| 36 message_loop_->PostTask( | |
| 37 FROM_HERE, | |
| 38 NewRunnableMethod(this, | |
| 39 &OmxVideoDecoder::Initialize, | |
| 40 make_scoped_refptr(demuxer_stream), | |
| 41 callback, stats_callback)); | |
| 42 return; | |
| 43 } | |
| 44 | |
| 45 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
| 46 DCHECK(!demuxer_stream_); | |
| 47 DCHECK(!initialize_callback_.get()); | |
| 48 | |
| 49 initialize_callback_.reset(callback); | |
| 50 statistics_callback_.reset(stats_callback); | |
| 51 demuxer_stream_ = demuxer_stream; | |
| 52 | |
| 53 // We require bit stream converter for openmax hardware decoder. | |
| 54 demuxer_stream->EnableBitstreamConverter(); | |
| 55 | |
| 56 AVStream* av_stream = demuxer_stream->GetAVStream(); | |
| 57 if (!av_stream) { | |
| 58 VideoCodecInfo info = {0}; | |
| 59 OnInitializeComplete(info); | |
| 60 return; | |
| 61 } | |
| 62 | |
| 63 pts_stream_.Initialize(GetFrameDuration(av_stream)); | |
| 64 | |
| 65 int width = av_stream->codec->coded_width; | |
| 66 int height = av_stream->codec->coded_height; | |
| 67 if (width > Limits::kMaxDimension || | |
| 68 height > Limits::kMaxDimension || | |
| 69 (width * height) > Limits::kMaxCanvas) { | |
| 70 VideoCodecInfo info = {0}; | |
| 71 OnInitializeComplete(info); | |
| 72 return; | |
| 73 } | |
| 74 | |
| 75 VideoDecoderConfig config(CodecIDToVideoCodec(av_stream->codec->codec_id), | |
| 76 width, height, | |
| 77 av_stream->r_frame_rate.num, | |
| 78 av_stream->r_frame_rate.den, | |
| 79 av_stream->codec->extradata, | |
| 80 av_stream->codec->extradata_size); | |
| 81 decode_engine_->Initialize(message_loop_, this, NULL, config); | |
| 82 } | |
| 83 | |
| 84 void OmxVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { | |
| 85 // TODO(scherkus): Dedup this from FFmpegVideoDecoder::OnInitializeComplete. | |
| 86 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 87 DCHECK(initialize_callback_.get()); | |
| 88 | |
| 89 info_ = info; | |
| 90 AutoCallbackRunner done_runner(initialize_callback_.release()); | |
| 91 | |
| 92 if (info.success) { | |
| 93 media_format_.SetAsInteger(MediaFormat::kWidth, | |
| 94 info.stream_info.surface_width); | |
| 95 media_format_.SetAsInteger(MediaFormat::kHeight, | |
| 96 info.stream_info.surface_height); | |
| 97 media_format_.SetAsInteger( | |
| 98 MediaFormat::kSurfaceType, | |
| 99 static_cast<int>(info.stream_info.surface_type)); | |
| 100 media_format_.SetAsInteger( | |
| 101 MediaFormat::kSurfaceFormat, | |
| 102 static_cast<int>(info.stream_info.surface_format)); | |
| 103 } else { | |
| 104 host()->SetError(PIPELINE_ERROR_DECODE); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 void OmxVideoDecoder::Stop(FilterCallback* callback) { | |
| 109 if (MessageLoop::current() != message_loop_) { | |
| 110 message_loop_->PostTask(FROM_HERE, | |
| 111 NewRunnableMethod(this, | |
| 112 &OmxVideoDecoder::Stop, | |
| 113 callback)); | |
| 114 return; | |
| 115 } | |
| 116 | |
| 117 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 118 DCHECK(!uninitialize_callback_.get()); | |
| 119 | |
| 120 uninitialize_callback_.reset(callback); | |
| 121 decode_engine_->Uninitialize(); | |
| 122 } | |
| 123 | |
| 124 void OmxVideoDecoder::OnUninitializeComplete() { | |
| 125 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 126 DCHECK(uninitialize_callback_.get()); | |
| 127 | |
| 128 AutoCallbackRunner done_runner(uninitialize_callback_.release()); | |
| 129 | |
| 130 // TODO(jiesun): Destroy the decoder context. | |
| 131 } | |
| 132 | |
| 133 void OmxVideoDecoder::Flush(FilterCallback* callback) { | |
| 134 if (MessageLoop::current() != message_loop_) { | |
| 135 message_loop_->PostTask(FROM_HERE, | |
| 136 NewRunnableMethod(this, | |
| 137 &OmxVideoDecoder::Flush, | |
| 138 callback)); | |
| 139 return; | |
| 140 } | |
| 141 | |
| 142 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 143 DCHECK(!flush_callback_.get()); | |
| 144 | |
| 145 flush_callback_.reset(callback); | |
| 146 | |
| 147 decode_engine_->Flush(); | |
| 148 } | |
| 149 | |
| 150 | |
| 151 void OmxVideoDecoder::OnFlushComplete() { | |
| 152 DCHECK(flush_callback_.get()); | |
| 153 | |
| 154 AutoCallbackRunner done_runner(flush_callback_.release()); | |
| 155 | |
| 156 pts_stream_.Flush(); | |
| 157 } | |
| 158 | |
| 159 void OmxVideoDecoder::Seek(base::TimeDelta time, const FilterStatusCB& cb) { | |
| 160 if (MessageLoop::current() != message_loop_) { | |
| 161 message_loop_->PostTask(FROM_HERE, | |
| 162 NewRunnableMethod(this, | |
| 163 &OmxVideoDecoder::Seek, | |
| 164 time, | |
| 165 cb)); | |
| 166 return; | |
| 167 } | |
| 168 | |
| 169 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 170 DCHECK(seek_cb_.is_null()); | |
| 171 | |
| 172 pts_stream_.Seek(time); | |
| 173 seek_cb_ = cb; | |
| 174 decode_engine_->Seek(); | |
| 175 } | |
| 176 | |
| 177 void OmxVideoDecoder::OnSeekComplete() { | |
| 178 DCHECK_EQ(MessageLoop::current(), message_loop_); | |
| 179 DCHECK(!seek_cb_.is_null()); | |
| 180 | |
| 181 ResetAndRunCB(&seek_cb_, PIPELINE_OK); | |
| 182 } | |
| 183 | |
| 184 void OmxVideoDecoder::OnError() { | |
| 185 NOTIMPLEMENTED(); | |
| 186 } | |
| 187 void OmxVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) { | |
| 188 NOTIMPLEMENTED(); | |
| 189 } | |
| 190 | |
| 191 void OmxVideoDecoder::ProduceVideoSample(scoped_refptr<Buffer> buffer) { | |
| 192 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
| 193 | |
| 194 // Issue more demux. | |
| 195 demuxer_stream_->Read(base::Bind(&OmxVideoDecoder::DemuxCompleteTask, this)); | |
| 196 } | |
| 197 | |
| 198 void OmxVideoDecoder::ConsumeVideoFrame(scoped_refptr<VideoFrame> frame, | |
| 199 const PipelineStatistics& statistics) { | |
| 200 DCHECK_EQ(message_loop_, MessageLoop::current()); | |
| 201 statistics_callback_->Run(statistics); | |
| 202 | |
| 203 if (frame.get()) { | |
| 204 pts_stream_.UpdatePtsAndDuration(frame.get()); | |
| 205 | |
| 206 frame->SetTimestamp(pts_stream_.current_pts()); | |
| 207 frame->SetDuration(pts_stream_.current_duration()); | |
| 208 } | |
| 209 | |
| 210 VideoFrameReady(frame); | |
| 211 } | |
| 212 | |
| 213 void OmxVideoDecoder::ProduceVideoFrame(scoped_refptr<VideoFrame> frame) { | |
| 214 DCHECK(decode_engine_.get()); | |
| 215 message_loop_->PostTask( | |
| 216 FROM_HERE, | |
| 217 NewRunnableMethod(decode_engine_.get(), | |
| 218 &VideoDecodeEngine::ProduceVideoFrame, frame)); | |
| 219 } | |
| 220 | |
| 221 bool OmxVideoDecoder::ProvidesBuffer() { | |
| 222 DCHECK(info_.success); | |
| 223 return info_.provides_buffers; | |
| 224 } | |
| 225 | |
| 226 const MediaFormat& OmxVideoDecoder::media_format() { | |
| 227 return media_format_; | |
| 228 } | |
| 229 | |
| 230 void OmxVideoDecoder::DemuxCompleteTask(Buffer* buffer) { | |
| 231 // We simply delicate the buffer to the right message loop. | |
| 232 scoped_refptr<Buffer> ref_buffer = buffer; | |
| 233 DCHECK(decode_engine_.get()); | |
| 234 message_loop_->PostTask( | |
| 235 FROM_HERE, | |
| 236 NewRunnableMethod(this, | |
| 237 &OmxVideoDecoder::ConsumeVideoSample, ref_buffer)); | |
| 238 } | |
| 239 | |
| 240 void OmxVideoDecoder::ConsumeVideoSample(scoped_refptr<Buffer> buffer) { | |
| 241 if (buffer.get()) | |
| 242 pts_stream_.EnqueuePts(buffer.get()); | |
| 243 decode_engine_->ConsumeVideoSample(buffer); | |
| 244 } | |
| 245 | |
| 246 } // namespace media | |
| 247 | |
| 248 // Disable refcounting for the decode engine because it only lives on the | |
| 249 // video decoder thread. | |
| 250 DISABLE_RUNNABLE_METHOD_REFCOUNT(media::VideoDecodeEngine); | |
| OLD | NEW |