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 |