OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/filters/ffmpeg_video_decoder.h" | 5 #include "media/filters/ffmpeg_video_decoder.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 | 125 |
126 // The FFmpeg API expects us to zero the data pointers in | 126 // The FFmpeg API expects us to zero the data pointers in |
127 // this callback | 127 // this callback |
128 memset(frame->data, 0, sizeof(frame->data)); | 128 memset(frame->data, 0, sizeof(frame->data)); |
129 frame->opaque = NULL; | 129 frame->opaque = NULL; |
130 } | 130 } |
131 | 131 |
132 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, | 132 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, |
133 const PipelineStatusCB& status_cb) { | 133 const PipelineStatusCB& status_cb) { |
134 DCHECK(message_loop_->BelongsToCurrentThread()); | 134 DCHECK(message_loop_->BelongsToCurrentThread()); |
135 DCHECK(read_cb_.is_null()); | 135 DCHECK(decode_cb_.is_null()); |
136 DCHECK(reset_cb_.is_null()); | 136 DCHECK(reset_cb_.is_null()); |
137 DCHECK(!config.is_encrypted()); | 137 DCHECK(!config.is_encrypted()); |
138 | 138 |
139 FFmpegGlue::InitializeFFmpeg(); | 139 FFmpegGlue::InitializeFFmpeg(); |
140 weak_this_ = weak_factory_.GetWeakPtr(); | 140 weak_this_ = weak_factory_.GetWeakPtr(); |
141 | 141 |
142 config_ = config; | 142 config_ = config; |
143 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); | 143 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); |
144 | 144 |
145 if (!config.IsValidConfig() || !ConfigureDecoder()) { | 145 if (!config.IsValidConfig() || !ConfigureDecoder()) { |
146 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 146 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
147 return; | 147 return; |
148 } | 148 } |
149 | 149 |
150 // Success! | 150 // Success! |
151 state_ = kNormal; | 151 state_ = kNormal; |
152 initialize_cb.Run(PIPELINE_OK); | 152 initialize_cb.Run(PIPELINE_OK); |
153 } | 153 } |
154 | 154 |
155 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 155 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
156 const ReadCB& read_cb) { | 156 const DecodeCB& decode_cb) { |
157 DCHECK(message_loop_->BelongsToCurrentThread()); | 157 DCHECK(message_loop_->BelongsToCurrentThread()); |
158 DCHECK(!read_cb.is_null()); | 158 DCHECK(!decode_cb.is_null()); |
159 CHECK_NE(state_, kUninitialized); | 159 CHECK_NE(state_, kUninitialized); |
160 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; | 160 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported."; |
161 read_cb_ = BindToCurrentLoop(read_cb); | 161 decode_cb_ = BindToCurrentLoop(decode_cb); |
162 | 162 |
163 if (state_ == kError) { | 163 if (state_ == kError) { |
164 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 164 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); |
165 return; | 165 return; |
166 } | 166 } |
167 | 167 |
168 // Return empty frames if decoding has finished. | 168 // Return empty frames if decoding has finished. |
169 if (state_ == kDecodeFinished) { | 169 if (state_ == kDecodeFinished) { |
170 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); | 170 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); |
171 return; | 171 return; |
172 } | 172 } |
173 | 173 |
174 DecodeBuffer(buffer); | 174 DecodeBuffer(buffer); |
175 } | 175 } |
176 | 176 |
177 void FFmpegVideoDecoder::Reset(const base::Closure& closure) { | 177 void FFmpegVideoDecoder::Reset(const base::Closure& closure) { |
178 DCHECK(message_loop_->BelongsToCurrentThread()); | 178 DCHECK(message_loop_->BelongsToCurrentThread()); |
179 DCHECK(reset_cb_.is_null()); | 179 DCHECK(reset_cb_.is_null()); |
180 reset_cb_ = BindToCurrentLoop(closure); | 180 reset_cb_ = BindToCurrentLoop(closure); |
181 | 181 |
182 // Defer the reset if a read is pending. | 182 // Defer the reset if a decode is pending. |
183 if (!read_cb_.is_null()) | 183 if (!decode_cb_.is_null()) |
184 return; | 184 return; |
185 | 185 |
186 DoReset(); | 186 DoReset(); |
187 } | 187 } |
188 | 188 |
189 void FFmpegVideoDecoder::DoReset() { | 189 void FFmpegVideoDecoder::DoReset() { |
190 DCHECK(read_cb_.is_null()); | 190 DCHECK(decode_cb_.is_null()); |
191 | 191 |
192 avcodec_flush_buffers(codec_context_); | 192 avcodec_flush_buffers(codec_context_); |
193 state_ = kNormal; | 193 state_ = kNormal; |
194 base::ResetAndReturn(&reset_cb_).Run(); | 194 base::ResetAndReturn(&reset_cb_).Run(); |
195 } | 195 } |
196 | 196 |
197 void FFmpegVideoDecoder::Stop(const base::Closure& closure) { | 197 void FFmpegVideoDecoder::Stop(const base::Closure& closure) { |
198 DCHECK(message_loop_->BelongsToCurrentThread()); | 198 DCHECK(message_loop_->BelongsToCurrentThread()); |
199 base::ScopedClosureRunner runner(BindToCurrentLoop(closure)); | 199 base::ScopedClosureRunner runner(BindToCurrentLoop(closure)); |
200 | 200 |
201 if (state_ == kUninitialized) | 201 if (state_ == kUninitialized) |
202 return; | 202 return; |
203 | 203 |
204 if (!read_cb_.is_null()) { | 204 if (!decode_cb_.is_null()) { |
205 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); | 205 base::ResetAndReturn(&decode_cb_).Run(kOk, NULL); |
206 // Reset is pending only when read is pending. | 206 // Reset is pending only when decode is pending. |
207 if (!reset_cb_.is_null()) | 207 if (!reset_cb_.is_null()) |
208 base::ResetAndReturn(&reset_cb_).Run(); | 208 base::ResetAndReturn(&reset_cb_).Run(); |
209 } | 209 } |
210 | 210 |
211 ReleaseFFmpegResources(); | 211 ReleaseFFmpegResources(); |
212 state_ = kUninitialized; | 212 state_ = kUninitialized; |
213 } | 213 } |
214 | 214 |
215 FFmpegVideoDecoder::~FFmpegVideoDecoder() { | 215 FFmpegVideoDecoder::~FFmpegVideoDecoder() { |
216 DCHECK_EQ(kUninitialized, state_); | 216 DCHECK_EQ(kUninitialized, state_); |
217 DCHECK(!codec_context_); | 217 DCHECK(!codec_context_); |
218 DCHECK(!av_frame_); | 218 DCHECK(!av_frame_); |
219 } | 219 } |
220 | 220 |
221 void FFmpegVideoDecoder::DecodeBuffer( | 221 void FFmpegVideoDecoder::DecodeBuffer( |
222 const scoped_refptr<DecoderBuffer>& buffer) { | 222 const scoped_refptr<DecoderBuffer>& buffer) { |
223 DCHECK(message_loop_->BelongsToCurrentThread()); | 223 DCHECK(message_loop_->BelongsToCurrentThread()); |
224 DCHECK_NE(state_, kUninitialized); | 224 DCHECK_NE(state_, kUninitialized); |
225 DCHECK_NE(state_, kDecodeFinished); | 225 DCHECK_NE(state_, kDecodeFinished); |
226 DCHECK_NE(state_, kError); | 226 DCHECK_NE(state_, kError); |
227 DCHECK(reset_cb_.is_null()); | 227 DCHECK(reset_cb_.is_null()); |
228 DCHECK(!read_cb_.is_null()); | 228 DCHECK(!decode_cb_.is_null()); |
229 DCHECK(buffer); | 229 DCHECK(buffer); |
230 | 230 |
231 // During decode, because reads are issued asynchronously, it is possible to | 231 // During decode, because reads are issued asynchronously, it is possible to |
232 // receive multiple end of stream buffers since each read is acked. When the | 232 // receive multiple end of stream buffers since each decode is acked. When the |
233 // first end of stream buffer is read, FFmpeg may still have frames queued | 233 // first end of stream buffer is read, FFmpeg may still have frames queued |
234 // up in the decoder so we need to go through the decode loop until it stops | 234 // up in the decoder so we need to go through the decode loop until it stops |
235 // giving sensible data. After that, the decoder should output empty | 235 // giving sensible data. After that, the decoder should output empty |
236 // frames. There are three states the decoder can be in: | 236 // frames. There are three states the decoder can be in: |
237 // | 237 // |
238 // kNormal: This is the starting state. Buffers are decoded. Decode errors | 238 // kNormal: This is the starting state. Buffers are decoded. Decode errors |
239 // are discarded. | 239 // are discarded. |
240 // kFlushCodec: There isn't any more input data. Call avcodec_decode_video2 | 240 // kFlushCodec: There isn't any more input data. Call avcodec_decode_video2 |
241 // until no more data is returned to flush out remaining | 241 // until no more data is returned to flush out remaining |
242 // frames. The input buffer is ignored at this point. | 242 // frames. The input buffer is ignored at this point. |
(...skipping 14 matching lines...) Expand all Loading... |
257 // Any time Reset() is called. | 257 // Any time Reset() is called. |
258 | 258 |
259 // Transition to kFlushCodec on the first end of stream buffer. | 259 // Transition to kFlushCodec on the first end of stream buffer. |
260 if (state_ == kNormal && buffer->end_of_stream()) { | 260 if (state_ == kNormal && buffer->end_of_stream()) { |
261 state_ = kFlushCodec; | 261 state_ = kFlushCodec; |
262 } | 262 } |
263 | 263 |
264 scoped_refptr<VideoFrame> video_frame; | 264 scoped_refptr<VideoFrame> video_frame; |
265 if (!FFmpegDecode(buffer, &video_frame)) { | 265 if (!FFmpegDecode(buffer, &video_frame)) { |
266 state_ = kError; | 266 state_ = kError; |
267 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 267 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); |
268 return; | 268 return; |
269 } | 269 } |
270 | 270 |
271 if (!video_frame.get()) { | 271 if (!video_frame.get()) { |
272 if (state_ == kFlushCodec) { | 272 if (state_ == kFlushCodec) { |
273 DCHECK(buffer->end_of_stream()); | 273 DCHECK(buffer->end_of_stream()); |
274 state_ = kDecodeFinished; | 274 state_ = kDecodeFinished; |
275 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); | 275 base::ResetAndReturn(&decode_cb_) |
| 276 .Run(kOk, VideoFrame::CreateEmptyFrame()); |
276 return; | 277 return; |
277 } | 278 } |
278 | 279 |
279 base::ResetAndReturn(&read_cb_).Run(kNotEnoughData, NULL); | 280 base::ResetAndReturn(&decode_cb_).Run(kNotEnoughData, NULL); |
280 return; | 281 return; |
281 } | 282 } |
282 | 283 |
283 base::ResetAndReturn(&read_cb_).Run(kOk, video_frame); | 284 base::ResetAndReturn(&decode_cb_).Run(kOk, video_frame); |
284 } | 285 } |
285 | 286 |
286 bool FFmpegVideoDecoder::FFmpegDecode( | 287 bool FFmpegVideoDecoder::FFmpegDecode( |
287 const scoped_refptr<DecoderBuffer>& buffer, | 288 const scoped_refptr<DecoderBuffer>& buffer, |
288 scoped_refptr<VideoFrame>* video_frame) { | 289 scoped_refptr<VideoFrame>* video_frame) { |
289 DCHECK(video_frame); | 290 DCHECK(video_frame); |
290 | 291 |
291 // Reset frame to default values. | 292 // Reset frame to default values. |
292 avcodec_get_frame_defaults(av_frame_); | 293 avcodec_get_frame_defaults(av_frame_); |
293 | 294 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
388 if (!codec || avcodec_open2(codec_context_, codec, NULL) < 0) { | 389 if (!codec || avcodec_open2(codec_context_, codec, NULL) < 0) { |
389 ReleaseFFmpegResources(); | 390 ReleaseFFmpegResources(); |
390 return false; | 391 return false; |
391 } | 392 } |
392 | 393 |
393 av_frame_ = avcodec_alloc_frame(); | 394 av_frame_ = avcodec_alloc_frame(); |
394 return true; | 395 return true; |
395 } | 396 } |
396 | 397 |
397 } // namespace media | 398 } // namespace media |
OLD | NEW |