| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 <deque> | 7 #include <deque> |
| 8 | 8 |
| 9 #include "base/task.h" | 9 #include "base/task.h" |
| 10 #include "media/base/callback.h" | 10 #include "media/base/callback.h" |
| 11 #include "media/base/filters.h" | 11 #include "media/base/filters.h" |
| 12 #include "media/base/filter_host.h" | 12 #include "media/base/filter_host.h" |
| 13 #include "media/base/limits.h" | 13 #include "media/base/limits.h" |
| 14 #include "media/base/media_format.h" | 14 #include "media/base/media_format.h" |
| 15 #include "media/base/video_frame.h" | 15 #include "media/base/video_frame.h" |
| 16 #include "media/ffmpeg/ffmpeg_common.h" | 16 #include "media/ffmpeg/ffmpeg_common.h" |
| 17 #include "media/ffmpeg/ffmpeg_util.h" | 17 #include "media/ffmpeg/ffmpeg_util.h" |
| 18 #include "media/filters/ffmpeg_interfaces.h" | 18 #include "media/filters/ffmpeg_interfaces.h" |
| 19 #include "media/video/ffmpeg_video_decode_engine.h" | 19 #include "media/video/ffmpeg_video_decode_engine.h" |
| 20 #include "media/video/video_decode_context.h" | 20 #include "media/video/video_decode_context.h" |
| 21 | 21 |
| 22 namespace media { | 22 namespace media { |
| 23 | 23 |
| 24 FFmpegVideoDecoder::FFmpegVideoDecoder(VideoDecodeContext* decode_context) | 24 FFmpegVideoDecoder::FFmpegVideoDecoder(MessageLoop* message_loop, |
| 25 : width_(0), | 25 VideoDecodeContext* decode_context) |
| 26 : message_loop_(message_loop), |
| 27 width_(0), |
| 26 height_(0), | 28 height_(0), |
| 27 time_base_(new AVRational()), | 29 time_base_(new AVRational()), |
| 28 state_(kUnInitialized), | 30 state_(kUnInitialized), |
| 29 decode_engine_(new FFmpegVideoDecodeEngine()), | 31 decode_engine_(new FFmpegVideoDecodeEngine()), |
| 30 decode_context_(decode_context) { | 32 decode_context_(decode_context) { |
| 31 memset(&info_, 0, sizeof(info_)); | 33 memset(&info_, 0, sizeof(info_)); |
| 32 } | 34 } |
| 33 | 35 |
| 34 FFmpegVideoDecoder::~FFmpegVideoDecoder() { | 36 FFmpegVideoDecoder::~FFmpegVideoDecoder() { |
| 35 } | 37 } |
| 36 | 38 |
| 37 void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, | 39 void FFmpegVideoDecoder::Initialize(DemuxerStream* demuxer_stream, |
| 38 FilterCallback* callback) { | 40 FilterCallback* callback) { |
| 39 if (MessageLoop::current() != message_loop()) { | 41 if (MessageLoop::current() != message_loop_) { |
| 40 message_loop()->PostTask( | 42 message_loop_->PostTask( |
| 41 FROM_HERE, | 43 FROM_HERE, |
| 42 NewRunnableMethod(this, | 44 NewRunnableMethod(this, |
| 43 &FFmpegVideoDecoder::Initialize, | 45 &FFmpegVideoDecoder::Initialize, |
| 44 make_scoped_refptr(demuxer_stream), | 46 make_scoped_refptr(demuxer_stream), |
| 45 callback)); | 47 callback)); |
| 46 return; | 48 return; |
| 47 } | 49 } |
| 48 | 50 |
| 49 DCHECK_EQ(MessageLoop::current(), message_loop()); | 51 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 50 DCHECK(!demuxer_stream_); | 52 DCHECK(!demuxer_stream_); |
| 51 DCHECK(!initialize_callback_.get()); | 53 DCHECK(!initialize_callback_.get()); |
| 52 | 54 |
| 53 demuxer_stream_ = demuxer_stream; | 55 demuxer_stream_ = demuxer_stream; |
| 54 initialize_callback_.reset(callback); | 56 initialize_callback_.reset(callback); |
| 55 | 57 |
| 56 // Get the AVStream by querying for the provider interface. | 58 // Get the AVStream by querying for the provider interface. |
| 57 AVStreamProvider* av_stream_provider; | 59 AVStreamProvider* av_stream_provider; |
| 58 if (!demuxer_stream->QueryInterface(&av_stream_provider)) { | 60 if (!demuxer_stream->QueryInterface(&av_stream_provider)) { |
| 59 VideoCodecInfo info = {0}; | 61 VideoCodecInfo info = {0}; |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 config.codec = kCodecMPEG4; break; | 93 config.codec = kCodecMPEG4; break; |
| 92 case CODEC_ID_VP8: | 94 case CODEC_ID_VP8: |
| 93 config.codec = kCodecVP8; break; | 95 config.codec = kCodecVP8; break; |
| 94 default: | 96 default: |
| 95 NOTREACHED(); | 97 NOTREACHED(); |
| 96 } | 98 } |
| 97 config.opaque_context = av_stream; | 99 config.opaque_context = av_stream; |
| 98 config.width = width_; | 100 config.width = width_; |
| 99 config.height = height_; | 101 config.height = height_; |
| 100 state_ = kInitializing; | 102 state_ = kInitializing; |
| 101 decode_engine_->Initialize(message_loop(), this, NULL, config); | 103 decode_engine_->Initialize(message_loop_, this, NULL, config); |
| 102 } | 104 } |
| 103 | 105 |
| 104 void FFmpegVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { | 106 void FFmpegVideoDecoder::OnInitializeComplete(const VideoCodecInfo& info) { |
| 105 DCHECK_EQ(MessageLoop::current(), message_loop()); | 107 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 106 DCHECK(initialize_callback_.get()); | 108 DCHECK(initialize_callback_.get()); |
| 107 | 109 |
| 108 info_ = info; // Save a copy. | 110 info_ = info; // Save a copy. |
| 109 | 111 |
| 110 if (info.success) { | 112 if (info.success) { |
| 111 media_format_.SetAsString(MediaFormat::kMimeType, | 113 media_format_.SetAsString(MediaFormat::kMimeType, |
| 112 mime_type::kUncompressedVideo); | 114 mime_type::kUncompressedVideo); |
| 113 media_format_.SetAsInteger(MediaFormat::kWidth, width_); | 115 media_format_.SetAsInteger(MediaFormat::kWidth, width_); |
| 114 media_format_.SetAsInteger(MediaFormat::kHeight, height_); | 116 media_format_.SetAsInteger(MediaFormat::kHeight, height_); |
| 115 media_format_.SetAsInteger( | 117 media_format_.SetAsInteger( |
| 116 MediaFormat::kSurfaceType, | 118 MediaFormat::kSurfaceType, |
| 117 static_cast<int>(info.stream_info.surface_type)); | 119 static_cast<int>(info.stream_info.surface_type)); |
| 118 media_format_.SetAsInteger( | 120 media_format_.SetAsInteger( |
| 119 MediaFormat::kSurfaceFormat, | 121 MediaFormat::kSurfaceFormat, |
| 120 static_cast<int>(info.stream_info.surface_format)); | 122 static_cast<int>(info.stream_info.surface_format)); |
| 121 state_ = kNormal; | 123 state_ = kNormal; |
| 122 } else { | 124 } else { |
| 123 host()->SetError(PIPELINE_ERROR_DECODE); | 125 host()->SetError(PIPELINE_ERROR_DECODE); |
| 124 } | 126 } |
| 125 | 127 |
| 126 initialize_callback_->Run(); | 128 initialize_callback_->Run(); |
| 127 initialize_callback_.reset(); | 129 initialize_callback_.reset(); |
| 128 } | 130 } |
| 129 | 131 |
| 130 void FFmpegVideoDecoder::Stop(FilterCallback* callback) { | 132 void FFmpegVideoDecoder::Stop(FilterCallback* callback) { |
| 131 if (MessageLoop::current() != message_loop()) { | 133 if (MessageLoop::current() != message_loop_) { |
| 132 message_loop()->PostTask(FROM_HERE, | 134 message_loop_->PostTask(FROM_HERE, |
| 133 NewRunnableMethod(this, | 135 NewRunnableMethod(this, |
| 134 &FFmpegVideoDecoder::Stop, | 136 &FFmpegVideoDecoder::Stop, |
| 135 callback)); | 137 callback)); |
| 136 return; | 138 return; |
| 137 } | 139 } |
| 138 | 140 |
| 139 DCHECK_EQ(MessageLoop::current(), message_loop()); | 141 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 140 DCHECK(!uninitialize_callback_.get()); | 142 DCHECK(!uninitialize_callback_.get()); |
| 141 | 143 |
| 142 uninitialize_callback_.reset(callback); | 144 uninitialize_callback_.reset(callback); |
| 143 if (state_ != kUnInitialized) | 145 if (state_ != kUnInitialized) |
| 144 decode_engine_->Uninitialize(); | 146 decode_engine_->Uninitialize(); |
| 145 else | 147 else |
| 146 OnUninitializeComplete(); | 148 OnUninitializeComplete(); |
| 147 } | 149 } |
| 148 | 150 |
| 149 void FFmpegVideoDecoder::OnUninitializeComplete() { | 151 void FFmpegVideoDecoder::OnUninitializeComplete() { |
| 150 DCHECK_EQ(MessageLoop::current(), message_loop()); | 152 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 151 DCHECK(uninitialize_callback_.get()); | 153 DCHECK(uninitialize_callback_.get()); |
| 152 | 154 |
| 153 AutoCallbackRunner done_runner(uninitialize_callback_.release()); | 155 AutoCallbackRunner done_runner(uninitialize_callback_.release()); |
| 154 state_ = kStopped; | 156 state_ = kStopped; |
| 155 | 157 |
| 156 // TODO(jiesun): Destroy the decoder context. | 158 // TODO(jiesun): Destroy the decoder context. |
| 157 } | 159 } |
| 158 | 160 |
| 159 void FFmpegVideoDecoder::Pause(FilterCallback* callback) { | 161 void FFmpegVideoDecoder::Pause(FilterCallback* callback) { |
| 160 if (MessageLoop::current() != message_loop()) { | 162 if (MessageLoop::current() != message_loop_) { |
| 161 message_loop()->PostTask(FROM_HERE, | 163 message_loop_->PostTask(FROM_HERE, |
| 162 NewRunnableMethod(this, | 164 NewRunnableMethod(this, |
| 163 &FFmpegVideoDecoder::Pause, | 165 &FFmpegVideoDecoder::Pause, |
| 164 callback)); | 166 callback)); |
| 165 return; | 167 return; |
| 166 } | 168 } |
| 167 | 169 |
| 168 AutoCallbackRunner done_runner(callback); | 170 AutoCallbackRunner done_runner(callback); |
| 169 state_ = kPausing; | 171 state_ = kPausing; |
| 170 } | 172 } |
| 171 | 173 |
| 172 void FFmpegVideoDecoder::Flush(FilterCallback* callback) { | 174 void FFmpegVideoDecoder::Flush(FilterCallback* callback) { |
| 173 if (MessageLoop::current() != message_loop()) { | 175 if (MessageLoop::current() != message_loop_) { |
| 174 message_loop()->PostTask(FROM_HERE, | 176 message_loop_->PostTask(FROM_HERE, |
| 175 NewRunnableMethod(this, | 177 NewRunnableMethod(this, |
| 176 &FFmpegVideoDecoder::Flush, | 178 &FFmpegVideoDecoder::Flush, |
| 177 callback)); | 179 callback)); |
| 178 return; | 180 return; |
| 179 } | 181 } |
| 180 | 182 |
| 181 DCHECK_EQ(MessageLoop::current(), message_loop()); | 183 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 182 DCHECK(!flush_callback_.get()); | 184 DCHECK(!flush_callback_.get()); |
| 183 | 185 |
| 184 state_ = kFlushing; | 186 state_ = kFlushing; |
| 185 | 187 |
| 186 FlushBuffers(); | 188 FlushBuffers(); |
| 187 | 189 |
| 188 flush_callback_.reset(callback); | 190 flush_callback_.reset(callback); |
| 189 | 191 |
| 190 decode_engine_->Flush(); | 192 decode_engine_->Flush(); |
| 191 } | 193 } |
| 192 | 194 |
| 193 void FFmpegVideoDecoder::OnFlushComplete() { | 195 void FFmpegVideoDecoder::OnFlushComplete() { |
| 194 DCHECK_EQ(MessageLoop::current(), message_loop()); | 196 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 195 DCHECK(flush_callback_.get()); | 197 DCHECK(flush_callback_.get()); |
| 196 | 198 |
| 197 AutoCallbackRunner done_runner(flush_callback_.release()); | 199 AutoCallbackRunner done_runner(flush_callback_.release()); |
| 198 | 200 |
| 199 // Everything in the presentation time queue is invalid, clear the queue. | 201 // Everything in the presentation time queue is invalid, clear the queue. |
| 200 while (!pts_heap_.IsEmpty()) | 202 while (!pts_heap_.IsEmpty()) |
| 201 pts_heap_.Pop(); | 203 pts_heap_.Pop(); |
| 202 | 204 |
| 203 // Mark flush operation had been done. | 205 // Mark flush operation had been done. |
| 204 state_ = kNormal; | 206 state_ = kNormal; |
| 205 } | 207 } |
| 206 | 208 |
| 207 void FFmpegVideoDecoder::Seek(base::TimeDelta time, | 209 void FFmpegVideoDecoder::Seek(base::TimeDelta time, |
| 208 FilterCallback* callback) { | 210 FilterCallback* callback) { |
| 209 if (MessageLoop::current() != message_loop()) { | 211 if (MessageLoop::current() != message_loop_) { |
| 210 message_loop()->PostTask(FROM_HERE, | 212 message_loop_->PostTask(FROM_HERE, |
| 211 NewRunnableMethod(this, | 213 NewRunnableMethod(this, |
| 212 &FFmpegVideoDecoder::Seek, | 214 &FFmpegVideoDecoder::Seek, |
| 213 time, | 215 time, |
| 214 callback)); | 216 callback)); |
| 215 return; | 217 return; |
| 216 } | 218 } |
| 217 | 219 |
| 218 DCHECK_EQ(MessageLoop::current(), message_loop()); | 220 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 219 DCHECK(!seek_callback_.get()); | 221 DCHECK(!seek_callback_.get()); |
| 220 | 222 |
| 221 seek_callback_.reset(callback); | 223 seek_callback_.reset(callback); |
| 222 decode_engine_->Seek(); | 224 decode_engine_->Seek(); |
| 223 } | 225 } |
| 224 | 226 |
| 225 void FFmpegVideoDecoder::OnSeekComplete() { | 227 void FFmpegVideoDecoder::OnSeekComplete() { |
| 226 DCHECK_EQ(MessageLoop::current(), message_loop()); | 228 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 227 DCHECK(seek_callback_.get()); | 229 DCHECK(seek_callback_.get()); |
| 228 | 230 |
| 229 AutoCallbackRunner done_runner(seek_callback_.release()); | 231 AutoCallbackRunner done_runner(seek_callback_.release()); |
| 230 } | 232 } |
| 231 | 233 |
| 232 void FFmpegVideoDecoder::OnError() { | 234 void FFmpegVideoDecoder::OnError() { |
| 233 NOTIMPLEMENTED(); | 235 NOTIMPLEMENTED(); |
| 234 } | 236 } |
| 235 | 237 |
| 236 void FFmpegVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) { | 238 void FFmpegVideoDecoder::OnFormatChange(VideoStreamInfo stream_info) { |
| 237 NOTIMPLEMENTED(); | 239 NOTIMPLEMENTED(); |
| 238 } | 240 } |
| 239 | 241 |
| 240 void FFmpegVideoDecoder::OnReadComplete(Buffer* buffer_in) { | 242 void FFmpegVideoDecoder::OnReadComplete(Buffer* buffer_in) { |
| 241 scoped_refptr<Buffer> buffer(buffer_in); | 243 scoped_refptr<Buffer> buffer(buffer_in); |
| 242 message_loop()->PostTask( | 244 message_loop_->PostTask( |
| 243 FROM_HERE, | 245 FROM_HERE, |
| 244 NewRunnableMethod(this, | 246 NewRunnableMethod(this, |
| 245 &FFmpegVideoDecoder::OnReadCompleteTask, | 247 &FFmpegVideoDecoder::OnReadCompleteTask, |
| 246 buffer)); | 248 buffer)); |
| 247 } | 249 } |
| 248 | 250 |
| 249 void FFmpegVideoDecoder::OnReadCompleteTask(scoped_refptr<Buffer> buffer) { | 251 void FFmpegVideoDecoder::OnReadCompleteTask(scoped_refptr<Buffer> buffer) { |
| 250 DCHECK_EQ(MessageLoop::current(), message_loop()); | 252 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 251 DCHECK_NE(state_, kStopped); // because of Flush() before Stop(). | 253 DCHECK_NE(state_, kStopped); // because of Flush() before Stop(). |
| 252 | 254 |
| 253 // During decode, because reads are issued asynchronously, it is possible to | 255 // During decode, because reads are issued asynchronously, it is possible to |
| 254 // receive multiple end of stream buffers since each read is acked. When the | 256 // receive multiple end of stream buffers since each read is acked. When the |
| 255 // first end of stream buffer is read, FFmpeg may still have frames queued | 257 // first end of stream buffer is read, FFmpeg may still have frames queued |
| 256 // up in the decoder so we need to go through the decode loop until it stops | 258 // up in the decoder so we need to go through the decode loop until it stops |
| 257 // giving sensible data. After that, the decoder should output empty | 259 // giving sensible data. After that, the decoder should output empty |
| 258 // frames. There are three states the decoder can be in: | 260 // frames. There are three states the decoder can be in: |
| 259 // | 261 // |
| 260 // kNormal: This is the starting state. Buffers are decoded. Decode errors | 262 // kNormal: This is the starting state. Buffers are decoded. Decode errors |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 // Otherwise, attempt to decode a single frame. | 296 // Otherwise, attempt to decode a single frame. |
| 295 decode_engine_->ConsumeVideoSample(buffer); | 297 decode_engine_->ConsumeVideoSample(buffer); |
| 296 } | 298 } |
| 297 | 299 |
| 298 const MediaFormat& FFmpegVideoDecoder::media_format() { | 300 const MediaFormat& FFmpegVideoDecoder::media_format() { |
| 299 return media_format_; | 301 return media_format_; |
| 300 } | 302 } |
| 301 | 303 |
| 302 void FFmpegVideoDecoder::ProduceVideoFrame( | 304 void FFmpegVideoDecoder::ProduceVideoFrame( |
| 303 scoped_refptr<VideoFrame> video_frame) { | 305 scoped_refptr<VideoFrame> video_frame) { |
| 304 if (MessageLoop::current() != message_loop()) { | 306 if (MessageLoop::current() != message_loop_) { |
| 305 message_loop()->PostTask( | 307 message_loop_->PostTask( |
| 306 FROM_HERE, | 308 FROM_HERE, |
| 307 NewRunnableMethod(this, | 309 NewRunnableMethod(this, |
| 308 &FFmpegVideoDecoder::ProduceVideoFrame, video_frame)); | 310 &FFmpegVideoDecoder::ProduceVideoFrame, video_frame)); |
| 309 return; | 311 return; |
| 310 } | 312 } |
| 311 | 313 |
| 312 DCHECK_EQ(MessageLoop::current(), message_loop()); | 314 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 313 | 315 |
| 314 // Synchronized flushing before stop should prevent this. | 316 // Synchronized flushing before stop should prevent this. |
| 315 DCHECK_NE(state_, kStopped); | 317 DCHECK_NE(state_, kStopped); |
| 316 | 318 |
| 317 // If the decoding is finished, we just always return empty frames. | 319 // If the decoding is finished, we just always return empty frames. |
| 318 if (state_ == kDecodeFinished) { | 320 if (state_ == kDecodeFinished) { |
| 319 // Signal VideoRenderer the end of the stream event. | 321 // Signal VideoRenderer the end of the stream event. |
| 320 scoped_refptr<VideoFrame> empty_frame; | 322 scoped_refptr<VideoFrame> empty_frame; |
| 321 VideoFrame::CreateEmptyFrame(&empty_frame); | 323 VideoFrame::CreateEmptyFrame(&empty_frame); |
| 322 VideoFrameReady(empty_frame); | 324 VideoFrameReady(empty_frame); |
| 323 | 325 |
| 324 // Fall through, because we still need to keep record of this frame. | 326 // Fall through, because we still need to keep record of this frame. |
| 325 } | 327 } |
| 326 | 328 |
| 327 // Notify decode engine the available of new frame. | 329 // Notify decode engine the available of new frame. |
| 328 decode_engine_->ProduceVideoFrame(video_frame); | 330 decode_engine_->ProduceVideoFrame(video_frame); |
| 329 } | 331 } |
| 330 | 332 |
| 331 void FFmpegVideoDecoder::ConsumeVideoFrame( | 333 void FFmpegVideoDecoder::ConsumeVideoFrame( |
| 332 scoped_refptr<VideoFrame> video_frame) { | 334 scoped_refptr<VideoFrame> video_frame) { |
| 333 DCHECK_EQ(MessageLoop::current(), message_loop()); | 335 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 334 DCHECK_NE(state_, kStopped); | 336 DCHECK_NE(state_, kStopped); |
| 335 | 337 |
| 336 if (video_frame.get()) { | 338 if (video_frame.get()) { |
| 337 if (kPausing == state_ || kFlushing == state_) { | 339 if (kPausing == state_ || kFlushing == state_) { |
| 338 frame_queue_flushed_.push_back(video_frame); | 340 frame_queue_flushed_.push_back(video_frame); |
| 339 if (kFlushing == state_) | 341 if (kFlushing == state_) |
| 340 FlushBuffers(); | 342 FlushBuffers(); |
| 341 return; | 343 return; |
| 342 } | 344 } |
| 343 | 345 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 358 // Signal VideoRenderer the end of the stream event. | 360 // Signal VideoRenderer the end of the stream event. |
| 359 scoped_refptr<VideoFrame> video_frame; | 361 scoped_refptr<VideoFrame> video_frame; |
| 360 VideoFrame::CreateEmptyFrame(&video_frame); | 362 VideoFrame::CreateEmptyFrame(&video_frame); |
| 361 VideoFrameReady(video_frame); | 363 VideoFrameReady(video_frame); |
| 362 } | 364 } |
| 363 } | 365 } |
| 364 } | 366 } |
| 365 | 367 |
| 366 void FFmpegVideoDecoder::ProduceVideoSample( | 368 void FFmpegVideoDecoder::ProduceVideoSample( |
| 367 scoped_refptr<Buffer> buffer) { | 369 scoped_refptr<Buffer> buffer) { |
| 368 DCHECK_EQ(MessageLoop::current(), message_loop()); | 370 DCHECK_EQ(MessageLoop::current(), message_loop_); |
| 369 DCHECK_NE(state_, kStopped); | 371 DCHECK_NE(state_, kStopped); |
| 370 | 372 |
| 371 demuxer_stream_->Read( | 373 demuxer_stream_->Read( |
| 372 NewCallback(this, &FFmpegVideoDecoder::OnReadComplete)); | 374 NewCallback(this, &FFmpegVideoDecoder::OnReadComplete)); |
| 373 } | 375 } |
| 374 | 376 |
| 375 FFmpegVideoDecoder::TimeTuple FFmpegVideoDecoder::FindPtsAndDuration( | 377 FFmpegVideoDecoder::TimeTuple FFmpegVideoDecoder::FindPtsAndDuration( |
| 376 const AVRational& time_base, | 378 const AVRational& time_base, |
| 377 PtsHeap* pts_heap, | 379 PtsHeap* pts_heap, |
| 378 const TimeTuple& last_pts, | 380 const TimeTuple& last_pts, |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 440 VideoFrameReady(video_frame); | 442 VideoFrameReady(video_frame); |
| 441 } | 443 } |
| 442 } | 444 } |
| 443 | 445 |
| 444 void FFmpegVideoDecoder::SetVideoDecodeEngineForTest( | 446 void FFmpegVideoDecoder::SetVideoDecodeEngineForTest( |
| 445 VideoDecodeEngine* engine) { | 447 VideoDecodeEngine* engine) { |
| 446 decode_engine_.reset(engine); | 448 decode_engine_.reset(engine); |
| 447 } | 449 } |
| 448 | 450 |
| 449 } // namespace media | 451 } // namespace media |
| OLD | NEW |