| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "media/filters/video_decoder_impl.h" | |
| 6 | |
| 7 #include "base/task.h" | |
| 8 #include "media/base/filters.h" | |
| 9 #include "media/base/limits.h" | |
| 10 #include "media/base/video_frame.h" | |
| 11 #include "media/ffmpeg/ffmpeg_common.h" | |
| 12 #include "media/filters/ffmpeg_interfaces.h" | |
| 13 #include "media/filters/video_decode_engine.h" | |
| 14 #include "media/ffmpeg/ffmpeg_util.h" | |
| 15 | |
| 16 namespace media { | |
| 17 | |
| 18 VideoDecoderImpl::VideoDecoderImpl(VideoDecodeEngine* engine) | |
| 19 : width_(0), | |
| 20 height_(0), | |
| 21 time_base_(new AVRational()), | |
| 22 state_(kNormal), | |
| 23 decode_engine_(engine) { | |
| 24 } | |
| 25 | |
| 26 VideoDecoderImpl::~VideoDecoderImpl() { | |
| 27 } | |
| 28 | |
| 29 void VideoDecoderImpl::DoInitialize(DemuxerStream* demuxer_stream, | |
| 30 bool* success, | |
| 31 Task* done_cb) { | |
| 32 AutoTaskRunner done_runner(done_cb); | |
| 33 *success = false; | |
| 34 | |
| 35 // Get the AVStream by querying for the provider interface. | |
| 36 AVStreamProvider* av_stream_provider; | |
| 37 if (!demuxer_stream->QueryInterface(&av_stream_provider)) { | |
| 38 return; | |
| 39 } | |
| 40 AVStream* av_stream = av_stream_provider->GetAVStream(); | |
| 41 | |
| 42 time_base_->den = av_stream->r_frame_rate.num; | |
| 43 time_base_->num = av_stream->r_frame_rate.den; | |
| 44 | |
| 45 // TODO(ajwong): We don't need these extra variables if |media_format_| has | |
| 46 // them. Remove. | |
| 47 width_ = av_stream->codec->width; | |
| 48 height_ = av_stream->codec->height; | |
| 49 if (width_ > Limits::kMaxDimension || | |
| 50 height_ > Limits::kMaxDimension || | |
| 51 (width_ * height_) > Limits::kMaxCanvas) { | |
| 52 return; | |
| 53 } | |
| 54 | |
| 55 // Only set kMimeType when derived class has not done so. | |
| 56 if (!media_format_.Contains(MediaFormat::kMimeType)) | |
| 57 media_format_.SetAsString(MediaFormat::kMimeType, | |
| 58 mime_type::kUncompressedVideo); | |
| 59 media_format_.SetAsInteger(MediaFormat::kWidth, width_); | |
| 60 media_format_.SetAsInteger(MediaFormat::kHeight, height_); | |
| 61 | |
| 62 decode_engine_->Initialize( | |
| 63 message_loop(), | |
| 64 av_stream, | |
| 65 NewCallback(this, &VideoDecoderImpl::OnEmptyBufferDone), | |
| 66 NewCallback(this, &VideoDecoderImpl::OnDecodeComplete), | |
| 67 NewRunnableMethod(this, | |
| 68 &VideoDecoderImpl::OnInitializeComplete, | |
| 69 success, | |
| 70 done_runner.release())); | |
| 71 } | |
| 72 | |
| 73 void VideoDecoderImpl::OnInitializeComplete(bool* success, Task* done_cb) { | |
| 74 AutoTaskRunner done_runner(done_cb); | |
| 75 | |
| 76 *success = decode_engine_->state() == VideoDecodeEngine::kNormal; | |
| 77 } | |
| 78 | |
| 79 void VideoDecoderImpl::DoSeek(base::TimeDelta time, Task* done_cb) { | |
| 80 // Everything in the presentation time queue is invalid, clear the queue. | |
| 81 while (!pts_heap_.IsEmpty()) | |
| 82 pts_heap_.Pop(); | |
| 83 | |
| 84 // We're back where we started. It should be completely safe to flush here | |
| 85 // since DecoderBase uses |expecting_discontinuous_| to verify that the next | |
| 86 // time DoDecode() is called we will have a discontinuous buffer. | |
| 87 // | |
| 88 // TODO(ajwong): Should we put a guard here to prevent leaving kError. | |
| 89 state_ = kNormal; | |
| 90 | |
| 91 decode_engine_->Flush(done_cb); | |
| 92 } | |
| 93 | |
| 94 void VideoDecoderImpl::DoDecode(Buffer* buffer) { | |
| 95 // TODO(ajwong): This DoDecode() and OnDecodeComplete() set of functions is | |
| 96 // too complicated to easily unittest. The test becomes fragile. Try to | |
| 97 // find a way to reorganize into smaller units for testing. | |
| 98 | |
| 99 // During decode, because reads are issued asynchronously, it is possible to | |
| 100 // receive multiple end of stream buffers since each read is acked. When the | |
| 101 // first end of stream buffer is read, FFmpeg may still have frames queued | |
| 102 // up in the decoder so we need to go through the decode loop until it stops | |
| 103 // giving sensible data. After that, the decoder should output empty | |
| 104 // frames. There are three states the decoder can be in: | |
| 105 // | |
| 106 // kNormal: This is the starting state. Buffers are decoded. Decode errors | |
| 107 // are discarded. | |
| 108 // kFlushCodec: There isn't any more input data. Call avcodec_decode_video2 | |
| 109 // until no more data is returned to flush out remaining | |
| 110 // frames. The input buffer is ignored at this point. | |
| 111 // kDecodeFinished: All calls return empty frames. | |
| 112 // | |
| 113 // These are the possible state transitions. | |
| 114 // | |
| 115 // kNormal -> kFlushCodec: | |
| 116 // When buffer->IsEndOfStream() is first true. | |
| 117 // kNormal -> kDecodeFinished: | |
| 118 // A catastrophic failure occurs, and decoding needs to stop. | |
| 119 // kFlushCodec -> kDecodeFinished: | |
| 120 // When avcodec_decode_video2() returns 0 data or errors out. | |
| 121 // (any state) -> kNormal: | |
| 122 // Any time buffer->IsDiscontinuous() is true. | |
| 123 // | |
| 124 // If the decoding is finished, we just always return empty frames. | |
| 125 if (state_ == kDecodeFinished) { | |
| 126 EnqueueEmptyFrame(); | |
| 127 OnEmptyBufferDone(NULL); | |
| 128 return; | |
| 129 } | |
| 130 | |
| 131 // Transition to kFlushCodec on the first end of stream buffer. | |
| 132 if (state_ == kNormal && buffer->IsEndOfStream()) { | |
| 133 state_ = kFlushCodec; | |
| 134 } | |
| 135 | |
| 136 // Push all incoming timestamps into the priority queue as long as we have | |
| 137 // not yet received an end of stream buffer. It is important that this line | |
| 138 // stay below the state transition into kFlushCodec done above. | |
| 139 // | |
| 140 // TODO(ajwong): This push logic, along with the pop logic below needs to | |
| 141 // be reevaluated to correctly handle decode errors. | |
| 142 if (state_ == kNormal && | |
| 143 buffer->GetTimestamp() != StreamSample::kInvalidTimestamp) { | |
| 144 pts_heap_.Push(buffer->GetTimestamp()); | |
| 145 } | |
| 146 | |
| 147 // Otherwise, attempt to decode a single frame. | |
| 148 decode_engine_->EmptyThisBuffer(buffer); | |
| 149 } | |
| 150 | |
| 151 void VideoDecoderImpl::OnDecodeComplete(scoped_refptr<VideoFrame> video_frame) { | |
| 152 if (video_frame.get()) { | |
| 153 // If we actually got data back, enqueue a frame. | |
| 154 last_pts_ = FindPtsAndDuration(*time_base_, &pts_heap_, last_pts_, | |
| 155 video_frame.get()); | |
| 156 | |
| 157 video_frame->SetTimestamp(last_pts_.timestamp); | |
| 158 video_frame->SetDuration(last_pts_.duration); | |
| 159 EnqueueVideoFrame(video_frame); | |
| 160 } else { | |
| 161 // When in kFlushCodec, any errored decode, or a 0-lengthed frame, | |
| 162 // is taken as a signal to stop decoding. | |
| 163 if (state_ == kFlushCodec) { | |
| 164 state_ = kDecodeFinished; | |
| 165 EnqueueEmptyFrame(); | |
| 166 } | |
| 167 } | |
| 168 | |
| 169 OnEmptyBufferDone(NULL); | |
| 170 } | |
| 171 | |
| 172 void VideoDecoderImpl::OnEmptyBufferDone(scoped_refptr<Buffer> buffer) { | |
| 173 // TODO(jiesun): what |DecodeBase::OnDecodeComplete| done is just | |
| 174 // what should be done in EmptyThisBufferCallback. | |
| 175 // Currently we just ignore the returned buffer. | |
| 176 DecoderBase<VideoDecoder, VideoFrame>::OnDecodeComplete(); | |
| 177 } | |
| 178 | |
| 179 void VideoDecoderImpl::EnqueueVideoFrame( | |
| 180 const scoped_refptr<VideoFrame>& video_frame) { | |
| 181 EnqueueResult(video_frame); | |
| 182 } | |
| 183 | |
| 184 void VideoDecoderImpl::EnqueueEmptyFrame() { | |
| 185 scoped_refptr<VideoFrame> video_frame; | |
| 186 VideoFrame::CreateEmptyFrame(&video_frame); | |
| 187 EnqueueResult(video_frame); | |
| 188 } | |
| 189 | |
| 190 VideoDecoderImpl::TimeTuple VideoDecoderImpl::FindPtsAndDuration( | |
| 191 const AVRational& time_base, | |
| 192 PtsHeap* pts_heap, | |
| 193 const TimeTuple& last_pts, | |
| 194 const VideoFrame* frame) { | |
| 195 TimeTuple pts; | |
| 196 | |
| 197 // First search the VideoFrame for the pts. This is the most authoritative. | |
| 198 // Make a special exclusion for the value pts == 0. Though this is | |
| 199 // technically a valid value, it seems a number of FFmpeg codecs will | |
| 200 // mistakenly always set pts to 0. | |
| 201 // | |
| 202 // TODO(scherkus): FFmpegVideoDecodeEngine should be able to detect this | |
| 203 // situation and set the timestamp to kInvalidTimestamp. | |
| 204 DCHECK(frame); | |
| 205 base::TimeDelta timestamp = frame->GetTimestamp(); | |
| 206 if (timestamp != StreamSample::kInvalidTimestamp && | |
| 207 timestamp.ToInternalValue() != 0) { | |
| 208 pts.timestamp = timestamp; | |
| 209 } else if (!pts_heap->IsEmpty()) { | |
| 210 // If the frame did not have pts, try to get the pts from the |pts_heap|. | |
| 211 pts.timestamp = pts_heap->Top(); | |
| 212 pts_heap->Pop(); | |
| 213 } else if (last_pts.timestamp != StreamSample::kInvalidTimestamp && | |
| 214 last_pts.duration != StreamSample::kInvalidTimestamp) { | |
| 215 // Guess assuming this frame was the same as the last frame. | |
| 216 pts.timestamp = last_pts.timestamp + last_pts.duration; | |
| 217 } else { | |
| 218 // Now we really have no clue!!! Mark an invalid timestamp and let the | |
| 219 // video renderer handle it (i.e., drop frame). | |
| 220 pts.timestamp = StreamSample::kInvalidTimestamp; | |
| 221 } | |
| 222 | |
| 223 // Fill in the duration, using the frame itself as the authoratative source. | |
| 224 base::TimeDelta duration = frame->GetDuration(); | |
| 225 if (duration != StreamSample::kInvalidTimestamp && | |
| 226 duration.ToInternalValue() != 0) { | |
| 227 pts.duration = duration; | |
| 228 } else { | |
| 229 // Otherwise assume a normal frame duration. | |
| 230 pts.duration = ConvertTimestamp(time_base, 1); | |
| 231 } | |
| 232 | |
| 233 return pts; | |
| 234 } | |
| 235 | |
| 236 void VideoDecoderImpl::SignalPipelineError() { | |
| 237 host()->SetError(PIPELINE_ERROR_DECODE); | |
| 238 state_ = kDecodeFinished; | |
| 239 } | |
| 240 | |
| 241 void VideoDecoderImpl::SetVideoDecodeEngineForTest( | |
| 242 VideoDecodeEngine* engine) { | |
| 243 decode_engine_.reset(engine); | |
| 244 } | |
| 245 | |
| 246 } // namespace media | |
| OLD | NEW |