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 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
68 | 68 |
69 static size_t RoundUp(size_t value, size_t alignment) { | 69 static size_t RoundUp(size_t value, size_t alignment) { |
70 // Check that |alignment| is a power of 2. | 70 // Check that |alignment| is a power of 2. |
71 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); | 71 DCHECK((alignment + (alignment - 1)) == (alignment | (alignment - 1))); |
72 return ((value + (alignment - 1)) & ~(alignment - 1)); | 72 return ((value + (alignment - 1)) & ~(alignment - 1)); |
73 } | 73 } |
74 | 74 |
75 FFmpegVideoDecoder::FFmpegVideoDecoder( | 75 FFmpegVideoDecoder::FFmpegVideoDecoder( |
76 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 76 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) |
77 : task_runner_(task_runner), state_(kUninitialized), | 77 : task_runner_(task_runner), state_(kUninitialized), |
78 decode_nalus_(false) {} | 78 decode_nalus_(false), weak_factory_(this) {} |
79 | 79 |
80 int FFmpegVideoDecoder::GetVideoBuffer(struct AVCodecContext* codec_context, | 80 int FFmpegVideoDecoder::GetVideoBuffer(struct AVCodecContext* codec_context, |
81 AVFrame* frame, | 81 AVFrame* frame, |
82 int flags) { | 82 int flags) { |
83 // Don't use |codec_context_| here! With threaded decoding, | 83 // Don't use |codec_context_| here! With threaded decoding, |
84 // it will contain unsynchronized width/height/pix_fmt values, | 84 // it will contain unsynchronized width/height/pix_fmt values, |
85 // whereas |codec_context| contains the current threads's | 85 // whereas |codec_context| contains the current threads's |
86 // updated width/height/pix_fmt, which can change for adaptive | 86 // updated width/height/pix_fmt, which can change for adaptive |
87 // content. | 87 // content. |
88 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context->pix_fmt); | 88 VideoFrame::Format format = PixelFormatToVideoFormat(codec_context->pix_fmt); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
146 ReleaseVideoBufferImpl, | 146 ReleaseVideoBufferImpl, |
147 opaque, | 147 opaque, |
148 0); | 148 0); |
149 return 0; | 149 return 0; |
150 } | 150 } |
151 | 151 |
152 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, | 152 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, |
153 bool low_delay, | 153 bool low_delay, |
154 const PipelineStatusCB& status_cb, | 154 const PipelineStatusCB& status_cb, |
155 const OutputCB& output_cb) { | 155 const OutputCB& output_cb) { |
| 156 DVLOG(2) << __FUNCTION__; |
156 DCHECK(task_runner_->BelongsToCurrentThread()); | 157 DCHECK(task_runner_->BelongsToCurrentThread()); |
157 DCHECK(!config.is_encrypted()); | 158 DCHECK(!config.is_encrypted()); |
158 DCHECK(!output_cb.is_null()); | 159 DCHECK(!output_cb.is_null()); |
159 | 160 |
160 FFmpegGlue::InitializeFFmpeg(); | 161 FFmpegGlue::InitializeFFmpeg(); |
161 | 162 |
162 config_ = config; | 163 config_ = config; |
163 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); | 164 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); |
164 | 165 |
165 if (!config.IsValidConfig() || !ConfigureDecoder(low_delay)) { | 166 if (!config.IsValidConfig() || !ConfigureDecoder(low_delay)) { |
166 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); | 167 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); |
167 return; | 168 return; |
168 } | 169 } |
169 | 170 |
170 output_cb_ = BindToCurrentLoop(output_cb); | 171 output_cb_ = BindToCurrentLoop(output_cb); |
171 | 172 |
172 // Success! | 173 // Success! |
173 state_ = kNormal; | 174 state_ = kNormal; |
174 initialize_cb.Run(PIPELINE_OK); | 175 initialize_cb.Run(PIPELINE_OK); |
175 } | 176 } |
176 | 177 |
177 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 178 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
178 const DecodeCB& decode_cb) { | 179 const DecodeCB& decode_cb) { |
| 180 DVLOG(2) << __FUNCTION__; |
| 181 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 182 |
| 183 static int count = 1; |
| 184 count++; |
| 185 int delay = 1; |
| 186 if (count % 100 == 0) |
| 187 delay = 2000; |
| 188 |
| 189 //base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(delay)); |
| 190 //DecodeInternal(buffer, decode_cb); |
| 191 |
| 192 task_runner_->PostDelayedTask(FROM_HERE, |
| 193 base::Bind(&FFmpegVideoDecoder::DecodeInternal, |
| 194 weak_factory_.GetWeakPtr(), |
| 195 buffer, |
| 196 decode_cb), |
| 197 base::TimeDelta::FromMilliseconds(delay)); |
| 198 } |
| 199 |
| 200 void FFmpegVideoDecoder::DecodeInternal(const scoped_refptr<DecoderBuffer>& buff
er, |
| 201 const DecodeCB& decode_cb) { |
| 202 DVLOG(2) << __FUNCTION__; |
179 DCHECK(task_runner_->BelongsToCurrentThread()); | 203 DCHECK(task_runner_->BelongsToCurrentThread()); |
180 DCHECK(buffer); | 204 DCHECK(buffer); |
181 DCHECK(!decode_cb.is_null()); | 205 DCHECK(!decode_cb.is_null()); |
182 CHECK_NE(state_, kUninitialized); | 206 CHECK_NE(state_, kUninitialized); |
183 | 207 |
184 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb); | 208 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb); |
185 | 209 |
186 if (state_ == kError) { | 210 if (state_ == kError) { |
187 decode_cb_bound.Run(kDecodeError); | 211 decode_cb_bound.Run(kDecodeError); |
188 return; | 212 return; |
189 } | 213 } |
190 | 214 |
191 if (state_ == kDecodeFinished) { | 215 if (state_ == kDecodeFinished) { |
192 decode_cb_bound.Run(kOk); | 216 decode_cb_bound.Run(kOk); |
193 return; | 217 return; |
194 } | 218 } |
195 | 219 |
| 220 //base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(40)); |
| 221 |
196 DCHECK_EQ(state_, kNormal); | 222 DCHECK_EQ(state_, kNormal); |
197 | 223 |
198 // During decode, because reads are issued asynchronously, it is possible to | 224 // During decode, because reads are issued asynchronously, it is possible to |
199 // receive multiple end of stream buffers since each decode is acked. When the | 225 // receive multiple end of stream buffers since each decode is acked. When the |
200 // first end of stream buffer is read, FFmpeg may still have frames queued | 226 // first end of stream buffer is read, FFmpeg may still have frames queued |
201 // up in the decoder so we need to go through the decode loop until it stops | 227 // up in the decoder so we need to go through the decode loop until it stops |
202 // giving sensible data. After that, the decoder should output empty | 228 // giving sensible data. After that, the decoder should output empty |
203 // frames. There are three states the decoder can be in: | 229 // frames. There are three states the decoder can be in: |
204 // | 230 // |
205 // kNormal: This is the starting state. Buffers are decoded. Decode errors | 231 // kNormal: This is the starting state. Buffers are decoded. Decode errors |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 LOG(ERROR) << "Video frame was produced yet has invalid frame data."; | 327 LOG(ERROR) << "Video frame was produced yet has invalid frame data."; |
302 av_frame_unref(av_frame_.get()); | 328 av_frame_unref(av_frame_.get()); |
303 return false; | 329 return false; |
304 } | 330 } |
305 | 331 |
306 scoped_refptr<VideoFrame> frame = | 332 scoped_refptr<VideoFrame> frame = |
307 reinterpret_cast<VideoFrame*>(av_buffer_get_opaque(av_frame_->buf[0])); | 333 reinterpret_cast<VideoFrame*>(av_buffer_get_opaque(av_frame_->buf[0])); |
308 frame->set_timestamp( | 334 frame->set_timestamp( |
309 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); | 335 base::TimeDelta::FromMicroseconds(av_frame_->reordered_opaque)); |
310 *has_produced_frame = true; | 336 *has_produced_frame = true; |
| 337 |
311 output_cb_.Run(frame); | 338 output_cb_.Run(frame); |
312 | 339 |
313 av_frame_unref(av_frame_.get()); | 340 av_frame_unref(av_frame_.get()); |
314 return true; | 341 return true; |
315 } | 342 } |
316 | 343 |
317 void FFmpegVideoDecoder::ReleaseFFmpegResources() { | 344 void FFmpegVideoDecoder::ReleaseFFmpegResources() { |
318 codec_context_.reset(); | 345 codec_context_.reset(); |
319 av_frame_.reset(); | 346 av_frame_.reset(); |
320 } | 347 } |
(...skipping 20 matching lines...) Expand all Loading... |
341 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { | 368 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { |
342 ReleaseFFmpegResources(); | 369 ReleaseFFmpegResources(); |
343 return false; | 370 return false; |
344 } | 371 } |
345 | 372 |
346 av_frame_.reset(av_frame_alloc()); | 373 av_frame_.reset(av_frame_alloc()); |
347 return true; | 374 return true; |
348 } | 375 } |
349 | 376 |
350 } // namespace media | 377 } // namespace media |
OLD | NEW |