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 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 scoped_refptr<VideoFrame> video_frame; | 65 scoped_refptr<VideoFrame> video_frame; |
66 video_frame.swap(reinterpret_cast<VideoFrame**>(&opaque)); | 66 video_frame.swap(reinterpret_cast<VideoFrame**>(&opaque)); |
67 } | 67 } |
68 | 68 |
69 // static | 69 // static |
70 bool FFmpegVideoDecoder::IsCodecSupported(VideoCodec codec) { | 70 bool FFmpegVideoDecoder::IsCodecSupported(VideoCodec codec) { |
71 FFmpegGlue::InitializeFFmpeg(); | 71 FFmpegGlue::InitializeFFmpeg(); |
72 return avcodec_find_decoder(VideoCodecToCodecID(codec)) != nullptr; | 72 return avcodec_find_decoder(VideoCodecToCodecID(codec)) != nullptr; |
73 } | 73 } |
74 | 74 |
75 FFmpegVideoDecoder::FFmpegVideoDecoder( | 75 FFmpegVideoDecoder::FFmpegVideoDecoder() |
76 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) | 76 : state_(kUninitialized), decode_nalus_(false) { |
77 : task_runner_(task_runner), state_(kUninitialized), | 77 thread_checker_.DetachFromThread(); |
78 decode_nalus_(false) {} | 78 } |
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 const VideoPixelFormat format = | 88 const VideoPixelFormat format = |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 | 161 |
162 std::string FFmpegVideoDecoder::GetDisplayName() const { | 162 std::string FFmpegVideoDecoder::GetDisplayName() const { |
163 return "FFmpegVideoDecoder"; | 163 return "FFmpegVideoDecoder"; |
164 } | 164 } |
165 | 165 |
166 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, | 166 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, |
167 bool low_delay, | 167 bool low_delay, |
168 const SetCdmReadyCB& /* set_cdm_ready_cb */, | 168 const SetCdmReadyCB& /* set_cdm_ready_cb */, |
169 const InitCB& init_cb, | 169 const InitCB& init_cb, |
170 const OutputCB& output_cb) { | 170 const OutputCB& output_cb) { |
171 DCHECK(task_runner_->BelongsToCurrentThread()); | 171 DCHECK(thread_checker_.CalledOnValidThread()); |
172 DCHECK(config.IsValidConfig()); | 172 DCHECK(config.IsValidConfig()); |
173 DCHECK(!output_cb.is_null()); | 173 DCHECK(!output_cb.is_null()); |
174 | 174 |
175 InitCB bound_init_cb = BindToCurrentLoop(init_cb); | 175 InitCB bound_init_cb = BindToCurrentLoop(init_cb); |
176 | 176 |
177 if (config.is_encrypted()) { | 177 if (config.is_encrypted()) { |
178 bound_init_cb.Run(false); | 178 bound_init_cb.Run(false); |
179 return; | 179 return; |
180 } | 180 } |
181 | 181 |
182 FFmpegGlue::InitializeFFmpeg(); | 182 FFmpegGlue::InitializeFFmpeg(); |
183 config_ = config; | 183 config_ = config; |
184 | 184 |
185 // TODO(xhwang): Only set |config_| after we successfully configure the | 185 // TODO(xhwang): Only set |config_| after we successfully configure the |
186 // decoder. | 186 // decoder. |
187 if (!ConfigureDecoder(low_delay)) { | 187 if (!ConfigureDecoder(low_delay)) { |
188 bound_init_cb.Run(false); | 188 bound_init_cb.Run(false); |
189 return; | 189 return; |
190 } | 190 } |
191 | 191 |
192 output_cb_ = BindToCurrentLoop(output_cb); | 192 output_cb_ = BindToCurrentLoop(output_cb); |
193 | 193 |
194 // Success! | 194 // Success! |
195 state_ = kNormal; | 195 state_ = kNormal; |
196 bound_init_cb.Run(true); | 196 bound_init_cb.Run(true); |
197 } | 197 } |
198 | 198 |
199 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, | 199 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, |
200 const DecodeCB& decode_cb) { | 200 const DecodeCB& decode_cb) { |
201 DCHECK(task_runner_->BelongsToCurrentThread()); | 201 DCHECK(thread_checker_.CalledOnValidThread()); |
202 DCHECK(buffer.get()); | 202 DCHECK(buffer.get()); |
203 DCHECK(!decode_cb.is_null()); | 203 DCHECK(!decode_cb.is_null()); |
204 CHECK_NE(state_, kUninitialized); | 204 CHECK_NE(state_, kUninitialized); |
205 | 205 |
206 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb); | 206 DecodeCB decode_cb_bound = BindToCurrentLoop(decode_cb); |
207 | 207 |
208 if (state_ == kError) { | 208 if (state_ == kError) { |
209 decode_cb_bound.Run(kDecodeError); | 209 decode_cb_bound.Run(kDecodeError); |
210 return; | 210 return; |
211 } | 211 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
251 | 251 |
252 if (buffer->end_of_stream()) | 252 if (buffer->end_of_stream()) |
253 state_ = kDecodeFinished; | 253 state_ = kDecodeFinished; |
254 | 254 |
255 // VideoDecoderShim expects that |decode_cb| is called only after | 255 // VideoDecoderShim expects that |decode_cb| is called only after |
256 // |output_cb_|. | 256 // |output_cb_|. |
257 decode_cb_bound.Run(kOk); | 257 decode_cb_bound.Run(kOk); |
258 } | 258 } |
259 | 259 |
260 void FFmpegVideoDecoder::Reset(const base::Closure& closure) { | 260 void FFmpegVideoDecoder::Reset(const base::Closure& closure) { |
261 DCHECK(task_runner_->BelongsToCurrentThread()); | 261 DCHECK(thread_checker_.CalledOnValidThread()); |
262 | 262 |
263 avcodec_flush_buffers(codec_context_.get()); | 263 avcodec_flush_buffers(codec_context_.get()); |
264 state_ = kNormal; | 264 state_ = kNormal; |
265 task_runner_->PostTask(FROM_HERE, closure); | 265 // PostTask() to avoid calling |closure| inmediately. |
| 266 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure); |
266 } | 267 } |
267 | 268 |
268 FFmpegVideoDecoder::~FFmpegVideoDecoder() { | 269 FFmpegVideoDecoder::~FFmpegVideoDecoder() { |
269 DCHECK(task_runner_->BelongsToCurrentThread()); | 270 DCHECK(thread_checker_.CalledOnValidThread()); |
270 | 271 |
271 if (state_ != kUninitialized) | 272 if (state_ != kUninitialized) |
272 ReleaseFFmpegResources(); | 273 ReleaseFFmpegResources(); |
273 } | 274 } |
274 | 275 |
275 bool FFmpegVideoDecoder::FFmpegDecode( | 276 bool FFmpegVideoDecoder::FFmpegDecode( |
276 const scoped_refptr<DecoderBuffer>& buffer, | 277 const scoped_refptr<DecoderBuffer>& buffer, |
277 bool* has_produced_frame) { | 278 bool* has_produced_frame) { |
278 DCHECK(!*has_produced_frame); | 279 DCHECK(!*has_produced_frame); |
279 | 280 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
368 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { | 369 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { |
369 ReleaseFFmpegResources(); | 370 ReleaseFFmpegResources(); |
370 return false; | 371 return false; |
371 } | 372 } |
372 | 373 |
373 av_frame_.reset(av_frame_alloc()); | 374 av_frame_.reset(av_frame_alloc()); |
374 return true; | 375 return true; |
375 } | 376 } |
376 | 377 |
377 } // namespace media | 378 } // namespace media |
OLD | NEW |