| 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 // A test program that drives an OpenMAX video decoder module. This program | 5 // A test program that drives an OpenMAX video decoder module. This program |
| 6 // will take video in elementary stream and read into the decoder. | 6 // will take video in elementary stream and read into the decoder. |
| 7 // | 7 // |
| 8 // Run the following command to see usage: | 8 // Run the following command to see usage: |
| 9 // ./omx_test | 9 // ./omx_test |
| 10 | 10 |
| 11 #include "base/at_exit.h" | 11 #include "base/at_exit.h" |
| 12 #include "base/callback.h" | 12 #include "base/callback.h" |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/message_loop.h" | 14 #include "base/message_loop.h" |
| 15 #include "base/scoped_ptr.h" | 15 #include "base/scoped_ptr.h" |
| 16 #include "base/time.h" | 16 #include "base/time.h" |
| 17 #include "media/base/data_buffer.h" |
| 17 #include "media/base/media.h" | 18 #include "media/base/media.h" |
| 19 #include "media/base/video_frame.h" |
| 18 #include "media/ffmpeg/ffmpeg_common.h" | 20 #include "media/ffmpeg/ffmpeg_common.h" |
| 19 #include "media/ffmpeg/file_protocol.h" | 21 #include "media/ffmpeg/file_protocol.h" |
| 20 #include "media/filters/bitstream_converter.h" | 22 #include "media/filters/bitstream_converter.h" |
| 21 #include "media/omx/omx_codec.h" | 23 #include "media/filters/omx_video_decode_engine.h" |
| 22 #include "media/base/data_buffer.h" | |
| 23 #include "media/tools/omx_test/color_space_util.h" | 24 #include "media/tools/omx_test/color_space_util.h" |
| 24 #include "media/tools/omx_test/file_reader_util.h" | 25 #include "media/tools/omx_test/file_reader_util.h" |
| 25 #include "media/tools/omx_test/file_sink.h" | 26 #include "media/tools/omx_test/file_sink.h" |
| 26 | 27 |
| 27 using media::BlockFileReader; | 28 using media::BlockFileReader; |
| 29 using media::Buffer; |
| 30 using media::DataBuffer; |
| 28 using media::FFmpegFileReader; | 31 using media::FFmpegFileReader; |
| 29 using media::FileReader; | 32 using media::FileReader; |
| 30 using media::FileSink; | 33 using media::FileSink; |
| 31 using media::H264FileReader; | 34 using media::H264FileReader; |
| 32 using media::OmxCodec; | |
| 33 using media::OmxConfigurator; | 35 using media::OmxConfigurator; |
| 34 using media::OmxDecoderConfigurator; | 36 using media::OmxDecoderConfigurator; |
| 35 using media::OmxEncoderConfigurator; | 37 using media::OmxEncoderConfigurator; |
| 38 using media::OmxVideoDecodeEngine; |
| 39 using media::VideoFrame; |
| 36 using media::YuvFileReader; | 40 using media::YuvFileReader; |
| 37 using media::Buffer; | |
| 38 using media::DataBuffer; | |
| 39 | 41 |
| 40 // This is the driver object to feed the decoder with data from a file. | 42 // This is the driver object to feed the decoder with data from a file. |
| 41 // It also provides callbacks for the decoder to receive events from the | 43 // It also provides callbacks for the decoder to receive events from the |
| 42 // decoder. | 44 // decoder. |
| 43 class TestApp { | 45 // TODO(wjia): AVStream should be replaced with a new structure which is |
| 46 // neutral to any video decoder. Also change media.gyp correspondingly. |
| 47 class TestApp : public base::RefCountedThreadSafe<TestApp> { |
| 44 public: | 48 public: |
| 45 TestApp(OmxConfigurator* configurator, FileSink* file_sink, | 49 TestApp(AVStream* av_stream, |
| 50 FileSink* file_sink, |
| 46 FileReader* file_reader) | 51 FileReader* file_reader) |
| 47 : configurator_(configurator), | 52 : av_stream_(av_stream), |
| 48 file_reader_(file_reader), | 53 file_reader_(file_reader), |
| 49 file_sink_(file_sink), | 54 file_sink_(file_sink), |
| 50 stopped_(false), | 55 stopped_(false), |
| 51 error_(false) { | 56 error_(false) { |
| 52 } | 57 } |
| 53 | 58 |
| 54 bool Initialize() { | 59 bool Initialize() { |
| 55 if (!file_reader_->Initialize()) { | 60 if (!file_reader_->Initialize()) { |
| 56 file_reader_.reset(); | 61 file_reader_.reset(); |
| 57 LOG(ERROR) << "can't initialize file reader"; | 62 LOG(ERROR) << "can't initialize file reader"; |
| 58 return false;; | 63 return false;; |
| 59 } | 64 } |
| 60 | 65 |
| 61 if (!file_sink_->Initialize()) { | 66 if (!file_sink_->Initialize()) { |
| 62 LOG(ERROR) << "can't initialize output writer"; | 67 LOG(ERROR) << "can't initialize output writer"; |
| 63 return false; | 68 return false; |
| 64 } | 69 } |
| 65 return true; | 70 return true; |
| 66 } | 71 } |
| 67 | 72 |
| 73 void InitializeDoneCallback() { |
| 74 } |
| 75 |
| 68 void StopCallback() { | 76 void StopCallback() { |
| 69 // If this callback is received, mark the |stopped_| flag so that we don't | 77 // If this callback is received, mark the |stopped_| flag so that we don't |
| 70 // feed more buffers into the decoder. | 78 // feed more buffers into the decoder. |
| 71 // We need to exit the current message loop because we have no more work | 79 // We need to exit the current message loop because we have no more work |
| 72 // to do on the message loop. This is done by calling | 80 // to do on the message loop. This is done by calling |
| 73 // message_loop_.Quit(). | 81 // message_loop_.Quit(). |
| 74 stopped_ = true; | 82 stopped_ = true; |
| 75 message_loop_.Quit(); | 83 message_loop_.Quit(); |
| 76 } | 84 } |
| 77 | 85 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 91 | 99 |
| 92 DCHECK_EQ(input_format.video_header.width, | 100 DCHECK_EQ(input_format.video_header.width, |
| 93 output_format.video_header.width); | 101 output_format.video_header.width); |
| 94 DCHECK_EQ(input_format.video_header.height, | 102 DCHECK_EQ(input_format.video_header.height, |
| 95 output_format.video_header.height); | 103 output_format.video_header.height); |
| 96 | 104 |
| 97 file_sink_->UpdateSize(input_format.video_header.width, | 105 file_sink_->UpdateSize(input_format.video_header.width, |
| 98 input_format.video_header.height); | 106 input_format.video_header.height); |
| 99 } | 107 } |
| 100 | 108 |
| 101 void FeedCompleteCallback(scoped_refptr<Buffer> buffer) { | 109 void FeedDoneCallback(scoped_refptr<Buffer> buffer) { |
| 102 // We receive this callback when the decoder has consumed an input buffer. | 110 // We receive this callback when the decoder has consumed an input buffer. |
| 103 // In this case, delete the previous buffer and enqueue a new one. | 111 // In this case, delete the previous buffer and enqueue a new one. |
| 104 // There are some conditions we don't want to enqueue, for example when | 112 // There are some conditions we don't want to enqueue, for example when |
| 105 // the last buffer is an end-of-stream buffer, when we have stopped, and | 113 // the last buffer is an end-of-stream buffer, when we have stopped, and |
| 106 // when we have received an error. | 114 // when we have received an error. |
| 107 bool eos = buffer->IsEndOfStream(); | 115 bool eos = buffer->IsEndOfStream(); |
| 108 if (!eos && !stopped_ && !error_) | 116 if (!eos && !stopped_ && !error_) |
| 109 FeedInputBuffer(); | 117 FeedInputBuffer(); |
| 110 } | 118 } |
| 111 | 119 |
| 112 void ReadCompleteCallback(OMX_BUFFERHEADERTYPE* buffer) { | 120 void DecodeDoneCallback(scoped_refptr<VideoFrame> frame) { |
| 113 // This callback is received when the decoder has completed a decoding | 121 // This callback is received when the decoder has completed a decoding |
| 114 // task and given us some output data. The buffer is owned by the decoder. | 122 // task and given us some output data. The frame is owned by the decoder. |
| 115 if (stopped_ || error_) | 123 if (stopped_ || error_) |
| 116 return; | 124 return; |
| 117 | 125 |
| 118 if (!frame_count_) | 126 if (!frame_count_) |
| 119 first_sample_delivered_time_ = base::TimeTicks::HighResNow(); | 127 first_sample_delivered_time_ = base::TimeTicks::HighResNow(); |
| 120 | 128 |
| 121 // If we are readding to the end, then stop. | 129 // If we are readding to the end, then stop. |
| 122 if (buffer == NULL) { | 130 if (frame.get() == NULL) { |
| 123 codec_->Stop(NewCallback(this, &TestApp::StopCallback)); | 131 engine_->Stop(NewCallback(this, &TestApp::StopCallback)); |
| 124 return; | 132 return; |
| 125 } | 133 } |
| 126 | 134 |
| 127 if (file_sink_.get()) | 135 if (file_sink_.get()) { |
| 128 file_sink_->BufferReady(buffer->nFilledLen, buffer->pBuffer); | 136 for (size_t i = 0; i < frame->planes(); i++) { |
| 137 int plane_size = frame->width() * frame->height(); |
| 138 if (i > 0) plane_size >>= 2; |
| 139 file_sink_->BufferReady(plane_size, frame->data(i)); |
| 140 } |
| 141 } |
| 129 | 142 |
| 130 // could OMX IL return patial sample for decoder? | 143 // could OMX IL return patial sample for decoder? |
| 131 frame_count_++; | 144 frame_count_++; |
| 132 } | 145 } |
| 133 | 146 |
| 134 void FeedInputBuffer() { | 147 void FeedInputBuffer() { |
| 135 uint8* data; | 148 uint8* data; |
| 136 int read; | 149 int read; |
| 137 file_reader_->Read(&data, &read); | 150 file_reader_->Read(&data, &read); |
| 138 codec_->Feed(new DataBuffer(data, read)); | 151 engine_->EmptyThisBuffer(new DataBuffer(data, read)); |
| 139 } | 152 } |
| 140 | 153 |
| 141 void Run() { | 154 void Run() { |
| 142 StartProfiler(); | 155 StartProfiler(); |
| 143 | 156 |
| 144 // Setup the |codec_| with the message loop of the current thread. Also | 157 // Setup the |engine_| with the message loop of the current thread. Also |
| 145 // setup component name, codec format and callbacks. | 158 // setup codec format and callbacks. |
| 146 codec_ = new OmxCodec(&message_loop_); | 159 engine_ = new OmxVideoDecodeEngine(); |
| 147 codec_->Setup(configurator_.get(), | 160 engine_->Initialize(&message_loop_, |
| 148 NewCallback(this, &TestApp::FeedCompleteCallback), | 161 av_stream_.get(), |
| 149 NewCallback(this, &TestApp::ReadCompleteCallback)); | 162 NewCallback(this, &TestApp::FeedDoneCallback), |
| 150 codec_->SetErrorCallback(NewCallback(this, &TestApp::ErrorCallback)); | 163 NewCallback(this, &TestApp::DecodeDoneCallback), |
| 151 codec_->SetFormatCallback(NewCallback(this, &TestApp::FormatCallback)); | 164 NewRunnableMethod(this, |
| 165 &TestApp::InitializeDoneCallback)); |
| 152 | 166 |
| 153 // Start the |codec_|. | |
| 154 codec_->Start(); | |
| 155 for (int i = 0; i < 20; ++i) | 167 for (int i = 0; i < 20; ++i) |
| 156 FeedInputBuffer(); | 168 FeedInputBuffer(); |
| 157 | 169 |
| 158 // Execute the message loop so that we can run tasks on it. This call | 170 // Execute the message loop so that we can run tasks on it. This call |
| 159 // will return when we call message_loop_.Quit(). | 171 // will return when we call message_loop_.Quit(). |
| 160 message_loop_.Run(); | 172 message_loop_.Run(); |
| 161 | 173 |
| 162 StopProfiler(); | 174 StopProfiler(); |
| 163 } | 175 } |
| 164 | 176 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 177 } | 189 } |
| 178 base::TimeDelta delay = first_sample_delivered_time_ - start_time_; | 190 base::TimeDelta delay = first_sample_delivered_time_ - start_time_; |
| 179 printf("\n<<< frame delivered : %d >>>", frame_count_); | 191 printf("\n<<< frame delivered : %d >>>", frame_count_); |
| 180 printf("\n<<< time used(ms) : %d >>>", static_cast<int>(duration_ms)); | 192 printf("\n<<< time used(ms) : %d >>>", static_cast<int>(duration_ms)); |
| 181 printf("\n<<< fps : %d >>>", static_cast<int>(fps)); | 193 printf("\n<<< fps : %d >>>", static_cast<int>(fps)); |
| 182 printf("\n<<< initial delay used(us): %d >>>", | 194 printf("\n<<< initial delay used(us): %d >>>", |
| 183 static_cast<int>(delay.InMicroseconds())); | 195 static_cast<int>(delay.InMicroseconds())); |
| 184 printf("\n"); | 196 printf("\n"); |
| 185 } | 197 } |
| 186 | 198 |
| 187 scoped_refptr<OmxCodec> codec_; | 199 scoped_refptr<OmxVideoDecodeEngine> engine_; |
| 188 MessageLoop message_loop_; | 200 MessageLoop message_loop_; |
| 189 scoped_ptr<OmxConfigurator> configurator_; | 201 scoped_ptr<AVStream> av_stream_; |
| 190 scoped_ptr<FileReader> file_reader_; | 202 scoped_ptr<FileReader> file_reader_; |
| 191 scoped_ptr<FileSink> file_sink_; | 203 scoped_ptr<FileSink> file_sink_; |
| 192 | 204 |
| 193 // Internal states for execution. | 205 // Internal states for execution. |
| 194 bool stopped_; | 206 bool stopped_; |
| 195 bool error_; | 207 bool error_; |
| 196 | 208 |
| 197 // Counters for performance. | 209 // Counters for performance. |
| 198 base::TimeTicks start_time_; | 210 base::TimeTicks start_time_; |
| 199 base::TimeTicks first_sample_delivered_time_; | 211 base::TimeTicks first_sample_delivered_time_; |
| 200 int frame_count_; | 212 int frame_count_; |
| 201 }; | 213 }; |
| 202 | 214 |
| 203 static std::string GetStringSwitch(const char* name) { | 215 static std::string GetStringSwitch(const char* name) { |
| 204 return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name); | 216 return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(name); |
| 205 } | 217 } |
| 206 | 218 |
| 207 static bool HasSwitch(const char* name) { | 219 static bool HasSwitch(const char* name) { |
| 208 return CommandLine::ForCurrentProcess()->HasSwitch(name); | 220 return CommandLine::ForCurrentProcess()->HasSwitch(name); |
| 209 } | 221 } |
| 210 | 222 |
| 211 static int GetIntSwitch(const char* name) { | 223 static int GetIntSwitch(const char* name) { |
| 212 if (HasSwitch(name)) | 224 if (HasSwitch(name)) |
| 213 return StringToInt(GetStringSwitch(name)); | 225 return StringToInt(GetStringSwitch(name)); |
| 214 return 0; | 226 return 0; |
| 215 } | 227 } |
| 216 | 228 |
| 217 static bool PrepareDecodeFormats(OmxConfigurator::MediaFormat* input, | 229 static bool PrepareDecodeFormats(AVStream *av_stream) { |
| 218 OmxConfigurator::MediaFormat* output) { | |
| 219 std::string codec = GetStringSwitch("codec"); | 230 std::string codec = GetStringSwitch("codec"); |
| 220 input->codec = OmxConfigurator::kCodecNone; | 231 av_stream->codec->codec_id = CODEC_ID_NONE; |
| 221 if (codec == "h264") { | 232 if (codec == "h264") { |
| 222 input->codec = OmxConfigurator::kCodecH264; | 233 av_stream->codec->codec_id = CODEC_ID_H264; |
| 223 } else if (codec == "mpeg4") { | 234 } else if (codec == "mpeg4") { |
| 224 input->codec = OmxConfigurator::kCodecMpeg4; | 235 av_stream->codec->codec_id = CODEC_ID_MPEG4; |
| 225 } else if (codec == "h263") { | 236 } else if (codec == "h263") { |
| 226 input->codec = OmxConfigurator::kCodecH263; | 237 av_stream->codec->codec_id = CODEC_ID_H263; |
| 227 } else if (codec == "vc1") { | 238 } else if (codec == "vc1") { |
| 228 input->codec = OmxConfigurator::kCodecVc1; | 239 av_stream->codec->codec_id = CODEC_ID_VC1; |
| 229 } else { | 240 } else { |
| 230 LOG(ERROR) << "Unknown codec."; | 241 LOG(ERROR) << "Unknown codec."; |
| 231 return false; | 242 return false; |
| 232 } | 243 } |
| 233 output->codec = OmxConfigurator::kCodecRaw; | |
| 234 return true; | 244 return true; |
| 235 } | 245 } |
| 236 | 246 |
| 237 static bool PrepareEncodeFormats(OmxConfigurator::MediaFormat* input, | 247 static bool PrepareEncodeFormats(AVStream *av_stream) { |
| 238 OmxConfigurator::MediaFormat* output) { | 248 av_stream->codec->width = GetIntSwitch("width"); |
| 239 input->codec = OmxConfigurator::kCodecRaw; | 249 av_stream->codec->height = GetIntSwitch("height"); |
| 240 input->video_header.width = GetIntSwitch("width"); | 250 av_stream->avg_frame_rate.num = GetIntSwitch("framerate"); |
| 241 input->video_header.height = GetIntSwitch("height"); | 251 av_stream->avg_frame_rate.den = 1; |
| 242 input->video_header.frame_rate = GetIntSwitch("framerate"); | 252 |
| 243 // TODO(jiesun): make other format available. | 253 std::string codec = GetStringSwitch("codec"); |
| 244 output->codec = OmxConfigurator::kCodecMpeg4; | 254 av_stream->codec->codec_id = CODEC_ID_NONE; |
| 245 output->video_header.width = GetIntSwitch("width"); | 255 if (codec == "h264") { |
| 246 output->video_header.height = GetIntSwitch("height"); | 256 av_stream->codec->codec_id = CODEC_ID_H264; |
| 247 output->video_header.frame_rate = GetIntSwitch("framerate"); | 257 } else if (codec == "mpeg4") { |
| 258 av_stream->codec->codec_id = CODEC_ID_MPEG4; |
| 259 } else if (codec == "h263") { |
| 260 av_stream->codec->codec_id = CODEC_ID_H263; |
| 261 } else if (codec == "vc1") { |
| 262 av_stream->codec->codec_id = CODEC_ID_VC1; |
| 263 } else { |
| 264 LOG(ERROR) << "Unknown codec."; |
| 265 return false; |
| 266 } |
| 248 // TODO(jiesun): assume constant bitrate now. | 267 // TODO(jiesun): assume constant bitrate now. |
| 249 output->video_header.bit_rate = GetIntSwitch("bitrate"); | 268 av_stream->codec->bit_rate = GetIntSwitch("bitrate"); |
| 250 // TODO(jiesun): one I frame per second now. make it configurable. | 269 |
| 251 output->video_header.i_dist = output->video_header.frame_rate; | 270 // TODO(wjia): add more configurations needed by encoder |
| 252 // TODO(jiesun): disable B frame now. does they support it? | |
| 253 output->video_header.p_dist = 0; | |
| 254 return true; | 271 return true; |
| 255 } | 272 } |
| 256 | 273 |
| 257 static bool InitFFmpeg() { | 274 static bool InitFFmpeg() { |
| 258 if (!media::InitializeMediaLibrary(FilePath())) | 275 if (!media::InitializeMediaLibrary(FilePath())) |
| 259 return false; | 276 return false; |
| 260 avcodec_init(); | 277 avcodec_init(); |
| 261 av_register_all(); | 278 av_register_all(); |
| 262 av_register_protocol(&kFFmpegFileProtocol); | 279 av_register_protocol(&kFFmpegFileProtocol); |
| 263 return true; | 280 return true; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 return false; | 338 return false; |
| 322 } | 339 } |
| 323 | 340 |
| 324 // If FFmpeg should be used for demuxing load the library here and do | 341 // If FFmpeg should be used for demuxing load the library here and do |
| 325 // the initialization. | 342 // the initialization. |
| 326 if (use_ffmpeg && !InitFFmpeg()) { | 343 if (use_ffmpeg && !InitFFmpeg()) { |
| 327 LOG(ERROR) << "Unable to initialize the media library."; | 344 LOG(ERROR) << "Unable to initialize the media library."; |
| 328 return -1; | 345 return -1; |
| 329 } | 346 } |
| 330 | 347 |
| 331 // Set the media formats for I/O. | 348 // Create AVStream |
| 332 OmxConfigurator::MediaFormat input, output; | 349 AVStream *av_stream = new AVStream; |
| 333 memset(&input, 0, sizeof(input)); | 350 AVCodecContext *av_codec_context = new AVCodecContext; |
| 334 memset(&output, 0, sizeof(output)); | 351 memset(av_stream, 0, sizeof(AVStream)); |
| 352 memset(av_codec_context, 0, sizeof(AVCodecContext)); |
| 353 scoped_ptr<AVCodecContext> av_codec_context_deleter(av_codec_context); |
| 354 av_stream->codec = av_codec_context; |
| 355 av_codec_context->width = 320; |
| 356 av_codec_context->height = 240; |
| 335 if (encoder) | 357 if (encoder) |
| 336 PrepareEncodeFormats(&input, &output); | 358 PrepareEncodeFormats(av_stream); |
| 337 else | 359 else |
| 338 PrepareDecodeFormats(&input, &output); | 360 PrepareDecodeFormats(av_stream); |
| 339 | 361 |
| 340 // Creates the FileReader to read input file. | 362 // Creates the FileReader to read input file. |
| 341 FileReader* file_reader; | 363 FileReader* file_reader; |
| 342 if (encoder) { | 364 if (encoder) { |
| 343 file_reader = new YuvFileReader( | 365 file_reader = new YuvFileReader( |
| 344 input_filename.c_str(), input.video_header.width, | 366 input_filename.c_str(), av_stream->codec->width, |
| 345 input.video_header.height, loop_count, enable_csc); | 367 av_stream->codec->height, loop_count, enable_csc); |
| 346 } else if (use_ffmpeg) { | 368 } else if (use_ffmpeg) { |
| 347 // Use ffmepg for reading. | 369 // Use ffmepg for reading. |
| 348 file_reader = new FFmpegFileReader(input_filename.c_str()); | 370 file_reader = new FFmpegFileReader(input_filename.c_str()); |
| 349 } else if (EndsWith(input_filename, ".264", false)) { | 371 } else if (EndsWith(input_filename, ".264", false)) { |
| 350 file_reader = new H264FileReader(input_filename.c_str()); | 372 file_reader = new H264FileReader(input_filename.c_str()); |
| 351 } else { | 373 } else { |
| 352 // Creates a reader that reads in blocks of 32KB. | 374 // Creates a reader that reads in blocks of 32KB. |
| 353 const int kReadSize = 32768; | 375 const int kReadSize = 32768; |
| 354 file_reader = new BlockFileReader(input_filename.c_str(), kReadSize); | 376 file_reader = new BlockFileReader(input_filename.c_str(), kReadSize); |
| 355 } | 377 } |
| 356 | 378 |
| 357 // Create the configurator. | |
| 358 OmxConfigurator* configurator; | |
| 359 if (encoder) | |
| 360 configurator = new OmxEncoderConfigurator(input, output); | |
| 361 else | |
| 362 configurator = new OmxDecoderConfigurator(input, output); | |
| 363 | |
| 364 // Create a file sink. | 379 // Create a file sink. |
| 365 FileSink* file_sink = new FileSink(output_filename, copy, enable_csc); | 380 FileSink* file_sink = new FileSink(output_filename, copy, enable_csc); |
| 366 | 381 |
| 367 // Create a test app object and initialize it. | 382 // Create a test app object and initialize it. |
| 368 TestApp test(configurator, file_sink, file_reader); | 383 scoped_refptr<TestApp> test = new TestApp(av_stream, file_sink, file_reader); |
| 369 if (!test.Initialize()) { | 384 if (!test->Initialize()) { |
| 370 LOG(ERROR) << "can't initialize this application"; | 385 LOG(ERROR) << "can't initialize this application"; |
| 371 return -1; | 386 return -1; |
| 372 } | 387 } |
| 373 | 388 |
| 374 // This will run the decoder until EOS is reached or an error | 389 // This will run the decoder until EOS is reached or an error |
| 375 // is encountered. | 390 // is encountered. |
| 376 test.Run(); | 391 test->Run(); |
| 377 return 0; | 392 return 0; |
| 378 } | 393 } |
| OLD | NEW |