Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(255)

Side by Side Diff: media/filters/ffmpeg_video_decoder.cc

Issue 65803002: Replace MessageLoopProxy with SingleThreadTaskRunner for media/filters/ + associated code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | media/filters/gpu_video_accelerator_factories.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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"
11 #include "base/callback_helpers.h" 11 #include "base/callback_helpers.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/location.h" 13 #include "base/location.h"
14 #include "base/message_loop/message_loop_proxy.h" 14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_number_conversions.h" 15 #include "base/strings/string_number_conversions.h"
16 #include "media/base/bind_to_loop.h" 16 #include "media/base/bind_to_loop.h"
17 #include "media/base/decoder_buffer.h" 17 #include "media/base/decoder_buffer.h"
18 #include "media/base/limits.h" 18 #include "media/base/limits.h"
19 #include "media/base/media_switches.h" 19 #include "media/base/media_switches.h"
20 #include "media/base/pipeline.h" 20 #include "media/base/pipeline.h"
21 #include "media/base/video_decoder_config.h" 21 #include "media/base/video_decoder_config.h"
22 #include "media/base/video_frame.h" 22 #include "media/base/video_frame.h"
23 #include "media/base/video_util.h" 23 #include "media/base/video_util.h"
24 #include "media/ffmpeg/ffmpeg_common.h" 24 #include "media/ffmpeg/ffmpeg_common.h"
(...skipping 23 matching lines...) Expand all
48 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads)); 48 std::string threads(cmd_line->GetSwitchValueASCII(switches::kVideoThreads));
49 if (threads.empty() || !base::StringToInt(threads, &decode_threads)) 49 if (threads.empty() || !base::StringToInt(threads, &decode_threads))
50 return decode_threads; 50 return decode_threads;
51 51
52 decode_threads = std::max(decode_threads, 0); 52 decode_threads = std::max(decode_threads, 0);
53 decode_threads = std::min(decode_threads, kMaxDecodeThreads); 53 decode_threads = std::min(decode_threads, kMaxDecodeThreads);
54 return decode_threads; 54 return decode_threads;
55 } 55 }
56 56
57 FFmpegVideoDecoder::FFmpegVideoDecoder( 57 FFmpegVideoDecoder::FFmpegVideoDecoder(
58 const scoped_refptr<base::MessageLoopProxy>& message_loop) 58 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
59 : message_loop_(message_loop), 59 : task_runner_(task_runner),
60 weak_factory_(this), 60 weak_factory_(this),
61 state_(kUninitialized) { 61 state_(kUninitialized) {
62 } 62 }
63 63
64 int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context, 64 int FFmpegVideoDecoder::GetVideoBuffer(AVCodecContext* codec_context,
65 AVFrame* frame) { 65 AVFrame* frame) {
66 // Don't use |codec_context_| here! With threaded decoding, 66 // Don't use |codec_context_| here! With threaded decoding,
67 // it will contain unsynchronized width/height/pix_fmt values, 67 // it will contain unsynchronized width/height/pix_fmt values,
68 // whereas |codec_context| contains the current threads's 68 // whereas |codec_context| contains the current threads's
69 // updated width/height/pix_fmt, which can change for adaptive 69 // updated width/height/pix_fmt, which can change for adaptive
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
121 video_frame.swap(reinterpret_cast<VideoFrame**>(&frame->opaque)); 121 video_frame.swap(reinterpret_cast<VideoFrame**>(&frame->opaque));
122 122
123 // The FFmpeg API expects us to zero the data pointers in 123 // The FFmpeg API expects us to zero the data pointers in
124 // this callback 124 // this callback
125 memset(frame->data, 0, sizeof(frame->data)); 125 memset(frame->data, 0, sizeof(frame->data));
126 frame->opaque = NULL; 126 frame->opaque = NULL;
127 } 127 }
128 128
129 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config, 129 void FFmpegVideoDecoder::Initialize(const VideoDecoderConfig& config,
130 const PipelineStatusCB& status_cb) { 130 const PipelineStatusCB& status_cb) {
131 DCHECK(message_loop_->BelongsToCurrentThread()); 131 DCHECK(task_runner_->BelongsToCurrentThread());
132 DCHECK(decode_cb_.is_null()); 132 DCHECK(decode_cb_.is_null());
133 DCHECK(reset_cb_.is_null()); 133 DCHECK(reset_cb_.is_null());
134 DCHECK(!config.is_encrypted()); 134 DCHECK(!config.is_encrypted());
135 135
136 FFmpegGlue::InitializeFFmpeg(); 136 FFmpegGlue::InitializeFFmpeg();
137 weak_this_ = weak_factory_.GetWeakPtr(); 137 weak_this_ = weak_factory_.GetWeakPtr();
138 138
139 config_ = config; 139 config_ = config;
140 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb); 140 PipelineStatusCB initialize_cb = BindToCurrentLoop(status_cb);
141 141
142 if (!config.IsValidConfig() || !ConfigureDecoder()) { 142 if (!config.IsValidConfig() || !ConfigureDecoder()) {
143 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED); 143 initialize_cb.Run(DECODER_ERROR_NOT_SUPPORTED);
144 return; 144 return;
145 } 145 }
146 146
147 // Success! 147 // Success!
148 state_ = kNormal; 148 state_ = kNormal;
149 initialize_cb.Run(PIPELINE_OK); 149 initialize_cb.Run(PIPELINE_OK);
150 } 150 }
151 151
152 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 152 void FFmpegVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer,
153 const DecodeCB& decode_cb) { 153 const DecodeCB& decode_cb) {
154 DCHECK(message_loop_->BelongsToCurrentThread()); 154 DCHECK(task_runner_->BelongsToCurrentThread());
155 DCHECK(!decode_cb.is_null()); 155 DCHECK(!decode_cb.is_null());
156 CHECK_NE(state_, kUninitialized); 156 CHECK_NE(state_, kUninitialized);
157 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported."; 157 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not supported.";
158 decode_cb_ = BindToCurrentLoop(decode_cb); 158 decode_cb_ = BindToCurrentLoop(decode_cb);
159 159
160 if (state_ == kError) { 160 if (state_ == kError) {
161 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL); 161 base::ResetAndReturn(&decode_cb_).Run(kDecodeError, NULL);
162 return; 162 return;
163 } 163 }
164 164
165 // Return empty frames if decoding has finished. 165 // Return empty frames if decoding has finished.
166 if (state_ == kDecodeFinished) { 166 if (state_ == kDecodeFinished) {
167 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEOSFrame()); 167 base::ResetAndReturn(&decode_cb_).Run(kOk, VideoFrame::CreateEOSFrame());
168 return; 168 return;
169 } 169 }
170 170
171 DecodeBuffer(buffer); 171 DecodeBuffer(buffer);
172 } 172 }
173 173
174 void FFmpegVideoDecoder::Reset(const base::Closure& closure) { 174 void FFmpegVideoDecoder::Reset(const base::Closure& closure) {
175 DCHECK(message_loop_->BelongsToCurrentThread()); 175 DCHECK(task_runner_->BelongsToCurrentThread());
176 DCHECK(reset_cb_.is_null()); 176 DCHECK(reset_cb_.is_null());
177 reset_cb_ = BindToCurrentLoop(closure); 177 reset_cb_ = BindToCurrentLoop(closure);
178 178
179 // Defer the reset if a decode is pending. 179 // Defer the reset if a decode is pending.
180 if (!decode_cb_.is_null()) 180 if (!decode_cb_.is_null())
181 return; 181 return;
182 182
183 DoReset(); 183 DoReset();
184 } 184 }
185 185
186 void FFmpegVideoDecoder::DoReset() { 186 void FFmpegVideoDecoder::DoReset() {
187 DCHECK(decode_cb_.is_null()); 187 DCHECK(decode_cb_.is_null());
188 188
189 avcodec_flush_buffers(codec_context_.get()); 189 avcodec_flush_buffers(codec_context_.get());
190 state_ = kNormal; 190 state_ = kNormal;
191 base::ResetAndReturn(&reset_cb_).Run(); 191 base::ResetAndReturn(&reset_cb_).Run();
192 } 192 }
193 193
194 void FFmpegVideoDecoder::Stop(const base::Closure& closure) { 194 void FFmpegVideoDecoder::Stop(const base::Closure& closure) {
195 DCHECK(message_loop_->BelongsToCurrentThread()); 195 DCHECK(task_runner_->BelongsToCurrentThread());
196 base::ScopedClosureRunner runner(BindToCurrentLoop(closure)); 196 base::ScopedClosureRunner runner(BindToCurrentLoop(closure));
197 197
198 if (state_ == kUninitialized) 198 if (state_ == kUninitialized)
199 return; 199 return;
200 200
201 if (!decode_cb_.is_null()) { 201 if (!decode_cb_.is_null()) {
202 base::ResetAndReturn(&decode_cb_).Run(kOk, NULL); 202 base::ResetAndReturn(&decode_cb_).Run(kOk, NULL);
203 // Reset is pending only when decode is pending. 203 // Reset is pending only when decode is pending.
204 if (!reset_cb_.is_null()) 204 if (!reset_cb_.is_null())
205 base::ResetAndReturn(&reset_cb_).Run(); 205 base::ResetAndReturn(&reset_cb_).Run();
206 } 206 }
207 207
208 ReleaseFFmpegResources(); 208 ReleaseFFmpegResources();
209 state_ = kUninitialized; 209 state_ = kUninitialized;
210 } 210 }
211 211
212 FFmpegVideoDecoder::~FFmpegVideoDecoder() { 212 FFmpegVideoDecoder::~FFmpegVideoDecoder() {
213 DCHECK_EQ(kUninitialized, state_); 213 DCHECK_EQ(kUninitialized, state_);
214 DCHECK(!codec_context_); 214 DCHECK(!codec_context_);
215 DCHECK(!av_frame_); 215 DCHECK(!av_frame_);
216 } 216 }
217 217
218 void FFmpegVideoDecoder::DecodeBuffer( 218 void FFmpegVideoDecoder::DecodeBuffer(
219 const scoped_refptr<DecoderBuffer>& buffer) { 219 const scoped_refptr<DecoderBuffer>& buffer) {
220 DCHECK(message_loop_->BelongsToCurrentThread()); 220 DCHECK(task_runner_->BelongsToCurrentThread());
221 DCHECK_NE(state_, kUninitialized); 221 DCHECK_NE(state_, kUninitialized);
222 DCHECK_NE(state_, kDecodeFinished); 222 DCHECK_NE(state_, kDecodeFinished);
223 DCHECK_NE(state_, kError); 223 DCHECK_NE(state_, kError);
224 DCHECK(reset_cb_.is_null()); 224 DCHECK(reset_cb_.is_null());
225 DCHECK(!decode_cb_.is_null()); 225 DCHECK(!decode_cb_.is_null());
226 DCHECK(buffer); 226 DCHECK(buffer);
227 227
228 // During decode, because reads are issued asynchronously, it is possible to 228 // During decode, because reads are issued asynchronously, it is possible to
229 // receive multiple end of stream buffers since each decode is acked. When the 229 // receive multiple end of stream buffers since each decode is acked. When the
230 // first end of stream buffer is read, FFmpeg may still have frames queued 230 // first end of stream buffer is read, FFmpeg may still have frames queued
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) { 378 if (!codec || avcodec_open2(codec_context_.get(), codec, NULL) < 0) {
379 ReleaseFFmpegResources(); 379 ReleaseFFmpegResources();
380 return false; 380 return false;
381 } 381 }
382 382
383 av_frame_.reset(av_frame_alloc()); 383 av_frame_.reset(av_frame_alloc());
384 return true; 384 return true;
385 } 385 }
386 386
387 } // namespace media 387 } // namespace media
OLDNEW
« no previous file with comments | « media/filters/ffmpeg_video_decoder.h ('k') | media/filters/gpu_video_accelerator_factories.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698