blob: 9240e64691e00b4471a4c2f5869d332eb6fc16af [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
mflodman@webrtc.org1f992802012-01-27 13:42:53 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pbos@webrtc.org8b062002013-07-12 08:28:10 +000011#include "webrtc/modules/utility/source/file_player_impl.h"
12#include "webrtc/system_wrappers/interface/trace.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000013
14#ifdef WEBRTC_MODULE_UTILITY_VIDEO
niklase@google.com470e71d2011-07-07 08:21:25 +000015 #include "frame_scaler.h"
16 #include "tick_util.h"
17 #include "video_coder.h"
18#endif
19
niklase@google.com470e71d2011-07-07 08:21:25 +000020namespace webrtc {
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000021FilePlayer* FilePlayer::CreateFilePlayer(uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +000022 FileFormats fileFormat)
23{
24 switch(fileFormat)
25 {
26 case kFileFormatWavFile:
27 case kFileFormatCompressedFile:
28 case kFileFormatPreencodedFile:
29 case kFileFormatPcm16kHzFile:
30 case kFileFormatPcm8kHzFile:
31 case kFileFormatPcm32kHzFile:
32 // audio formats
33 return new FilePlayerImpl(instanceID, fileFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +000034 case kFileFormatAviFile:
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +000035#ifdef WEBRTC_MODULE_UTILITY_VIDEO
niklase@google.com470e71d2011-07-07 08:21:25 +000036 return new VideoFilePlayerImpl(instanceID, fileFormat);
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +000037#else
38 WEBRTC_TRACE(kTraceError, kTraceFile, -1,
39 "Invalid file format: %d", kFileFormatAviFile);
40 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +000041 return NULL;
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +000042#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000043 }
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000044 assert(false);
45 return NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000046}
47
48void FilePlayer::DestroyFilePlayer(FilePlayer* player)
49{
50 delete player;
51}
52
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000053FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +000054 const FileFormats fileFormat)
55 : _instanceID(instanceID),
56 _fileFormat(fileFormat),
57 _fileModule(*MediaFile::CreateMediaFile(instanceID)),
58 _decodedLengthInMS(0),
59 _audioDecoder(instanceID),
60 _codec(),
61 _numberOf10MsPerFrame(0),
62 _numberOf10MsInDecoder(0),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +000063 _resampler(),
niklase@google.com470e71d2011-07-07 08:21:25 +000064 _scaling(1.0)
65{
66 _codec.plfreq = 0;
67}
68
69FilePlayerImpl::~FilePlayerImpl()
70{
71 MediaFile::DestroyMediaFile(&_fileModule);
72}
73
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000074int32_t FilePlayerImpl::Frequency() const
niklase@google.com470e71d2011-07-07 08:21:25 +000075{
76 if(_codec.plfreq == 0)
77 {
78 return -1;
79 }
80 // Make sure that sample rate is 8,16 or 32 kHz. E.g. WAVE files may have
81 // other sampling rates.
82 if(_codec.plfreq == 11000)
83 {
84 return 16000;
85 }
86 else if(_codec.plfreq == 22000)
87 {
88 return 32000;
89 }
90 else if(_codec.plfreq == 44000)
91 {
92 return 32000;
93 }
94 else if(_codec.plfreq == 48000)
95 {
96 return 32000;
97 }
98 else
99 {
100 return _codec.plfreq;
101 }
102}
103
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000104int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000105{
106 audioCodec = _codec;
107 return 0;
108}
109
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000110int32_t FilePlayerImpl::Get10msAudioFromFile(
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +0000111 int16_t* outBuffer,
112 int& lengthInSamples,
113 int frequencyInHz)
niklase@google.com470e71d2011-07-07 08:21:25 +0000114{
115 if(_codec.plfreq == 0)
116 {
117 WEBRTC_TRACE(kTraceWarning, kTraceVoice, _instanceID,
118 "FilePlayerImpl::Get10msAudioFromFile() playing not started!\
119 codecFreq = %d, wantedFreq = %d",
120 _codec.plfreq, frequencyInHz);
121 return -1;
122 }
123
124 AudioFrame unresampledAudioFrame;
125 if(STR_CASE_CMP(_codec.plname, "L16") == 0)
126 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000127 unresampledAudioFrame.sample_rate_hz_ = _codec.plfreq;
niklase@google.com470e71d2011-07-07 08:21:25 +0000128
129 // L16 is un-encoded data. Just pull 10 ms.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000130 uint32_t lengthInBytes =
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000131 sizeof(unresampledAudioFrame.data_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000132 if (_fileModule.PlayoutAudioData(
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000133 (int8_t*)unresampledAudioFrame.data_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000134 lengthInBytes) == -1)
135 {
136 // End of file reached.
137 return -1;
138 }
139 if(lengthInBytes == 0)
140 {
141 lengthInSamples = 0;
142 return 0;
143 }
144 // One sample is two bytes.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000145 unresampledAudioFrame.samples_per_channel_ =
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000146 (uint16_t)lengthInBytes >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000147
148 }else {
149 // Decode will generate 10 ms of audio data. PlayoutAudioData(..)
150 // expects a full frame. If the frame size is larger than 10 ms,
151 // PlayoutAudioData(..) data should be called proportionally less often.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000152 int16_t encodedBuffer[MAX_AUDIO_BUFFER_IN_SAMPLES];
153 uint32_t encodedLengthInBytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000154 if(++_numberOf10MsInDecoder >= _numberOf10MsPerFrame)
155 {
156 _numberOf10MsInDecoder = 0;
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000157 uint32_t bytesFromFile = sizeof(encodedBuffer);
158 if (_fileModule.PlayoutAudioData((int8_t*)encodedBuffer,
niklase@google.com470e71d2011-07-07 08:21:25 +0000159 bytesFromFile) == -1)
160 {
161 // End of file reached.
162 return -1;
163 }
164 encodedLengthInBytes = bytesFromFile;
165 }
166 if(_audioDecoder.Decode(unresampledAudioFrame,frequencyInHz,
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000167 (int8_t*)encodedBuffer,
niklase@google.com470e71d2011-07-07 08:21:25 +0000168 encodedLengthInBytes) == -1)
169 {
170 return -1;
171 }
172 }
173
174 int outLen = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000175 if(_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000176 frequencyInHz, kResamplerSynchronous))
177 {
178 WEBRTC_TRACE(kTraceWarning, kTraceVoice, _instanceID,
179 "FilePlayerImpl::Get10msAudioFromFile() unexpected codec");
180
181 // New sampling frequency. Update state.
182 outLen = frequencyInHz / 100;
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000183 memset(outBuffer, 0, outLen * sizeof(int16_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 return 0;
185 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000186 _resampler.Push(unresampledAudioFrame.data_,
187 unresampledAudioFrame.samples_per_channel_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000188 outBuffer,
189 MAX_AUDIO_BUFFER_IN_SAMPLES,
190 outLen);
191
192 lengthInSamples = outLen;
193
194 if(_scaling != 1.0)
195 {
196 for (int i = 0;i < outLen; i++)
197 {
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000198 outBuffer[i] = (int16_t)(outBuffer[i] * _scaling);
niklase@google.com470e71d2011-07-07 08:21:25 +0000199 }
200 }
201 _decodedLengthInMS += 10;
202 return 0;
203}
204
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000205int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback)
niklase@google.com470e71d2011-07-07 08:21:25 +0000206{
207 return _fileModule.SetModuleFileCallback(callback);
208}
209
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000210int32_t FilePlayerImpl::SetAudioScaling(float scaleFactor)
niklase@google.com470e71d2011-07-07 08:21:25 +0000211{
212 if((scaleFactor >= 0)&&(scaleFactor <= 2.0))
213 {
214 _scaling = scaleFactor;
215 return 0;
216 }
217 WEBRTC_TRACE(kTraceWarning, kTraceVoice, _instanceID,
218 "FilePlayerImpl::SetAudioScaling() not allowed scale factor");
219 return -1;
220}
221
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000222int32_t FilePlayerImpl::StartPlayingFile(const char* fileName,
223 bool loop,
224 uint32_t startPosition,
225 float volumeScaling,
226 uint32_t notification,
227 uint32_t stopPosition,
228 const CodecInst* codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000229{
230 if (_fileFormat == kFileFormatPcm16kHzFile ||
231 _fileFormat == kFileFormatPcm8kHzFile||
232 _fileFormat == kFileFormatPcm32kHzFile )
233 {
234 CodecInst codecInstL16;
235 strncpy(codecInstL16.plname,"L16",32);
236 codecInstL16.pltype = 93;
237 codecInstL16.channels = 1;
238
239 if (_fileFormat == kFileFormatPcm8kHzFile)
240 {
241 codecInstL16.rate = 128000;
242 codecInstL16.plfreq = 8000;
243 codecInstL16.pacsize = 80;
244
245 } else if(_fileFormat == kFileFormatPcm16kHzFile)
246 {
247 codecInstL16.rate = 256000;
248 codecInstL16.plfreq = 16000;
249 codecInstL16.pacsize = 160;
250
251 }else if(_fileFormat == kFileFormatPcm32kHzFile)
252 {
253 codecInstL16.rate = 512000;
254 codecInstL16.plfreq = 32000;
255 codecInstL16.pacsize = 160;
256 } else
257 {
258 WEBRTC_TRACE(kTraceError, kTraceVoice, _instanceID,
259 "FilePlayerImpl::StartPlayingFile() sample frequency\
260 specifed not supported for PCM format.");
261 return -1;
262 }
263
264 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
265 _fileFormat, &codecInstL16,
266 startPosition,
267 stopPosition) == -1)
268 {
269 WEBRTC_TRACE(
270 kTraceWarning,
271 kTraceVoice,
272 _instanceID,
273 "FilePlayerImpl::StartPlayingFile() failed to initialize file\
274 %s playout.", fileName);
275 return -1;
276 }
277 SetAudioScaling(volumeScaling);
278 }else if(_fileFormat == kFileFormatPreencodedFile)
279 {
280 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
281 _fileFormat, codecInst) == -1)
282 {
283 WEBRTC_TRACE(
284 kTraceWarning,
285 kTraceVoice,
286 _instanceID,
287 "FilePlayerImpl::StartPlayingPreEncodedFile() failed to\
288 initialize pre-encoded file %s playout.",
289 fileName);
290 return -1;
291 }
292 } else
293 {
294 CodecInst* no_inst = NULL;
295 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
296 _fileFormat, no_inst,
297 startPosition,
298 stopPosition) == -1)
299 {
300 WEBRTC_TRACE(
301 kTraceWarning,
302 kTraceVoice,
303 _instanceID,
304 "FilePlayerImpl::StartPlayingFile() failed to initialize file\
305 %s playout.", fileName);
306 return -1;
307 }
308 SetAudioScaling(volumeScaling);
309 }
310 if (SetUpAudioDecoder() == -1)
311 {
312 StopPlayingFile();
313 return -1;
314 }
315 return 0;
316}
317
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000318int32_t FilePlayerImpl::StartPlayingFile(InStream& sourceStream,
319 uint32_t startPosition,
320 float volumeScaling,
321 uint32_t notification,
322 uint32_t stopPosition,
323 const CodecInst* codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000324{
325 if (_fileFormat == kFileFormatPcm16kHzFile ||
326 _fileFormat == kFileFormatPcm32kHzFile ||
327 _fileFormat == kFileFormatPcm8kHzFile)
328 {
329 CodecInst codecInstL16;
330 strncpy(codecInstL16.plname,"L16",32);
331 codecInstL16.pltype = 93;
332 codecInstL16.channels = 1;
333
334 if (_fileFormat == kFileFormatPcm8kHzFile)
335 {
336 codecInstL16.rate = 128000;
337 codecInstL16.plfreq = 8000;
338 codecInstL16.pacsize = 80;
339
340 }else if (_fileFormat == kFileFormatPcm16kHzFile)
341 {
342 codecInstL16.rate = 256000;
343 codecInstL16.plfreq = 16000;
344 codecInstL16.pacsize = 160;
345
346 }else if (_fileFormat == kFileFormatPcm32kHzFile)
347 {
348 codecInstL16.rate = 512000;
349 codecInstL16.plfreq = 32000;
350 codecInstL16.pacsize = 160;
351 }else
352 {
353 WEBRTC_TRACE(
354 kTraceError,
355 kTraceVoice,
356 _instanceID,
357 "FilePlayerImpl::StartPlayingFile() sample frequency specifed\
358 not supported for PCM format.");
359 return -1;
360 }
361 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
362 _fileFormat, &codecInstL16,
363 startPosition,
364 stopPosition) == -1)
365 {
366 WEBRTC_TRACE(
367 kTraceError,
368 kTraceVoice,
369 _instanceID,
370 "FilePlayerImpl::StartPlayingFile() failed to initialize stream\
371 playout.");
372 return -1;
373 }
374
375 }else if(_fileFormat == kFileFormatPreencodedFile)
376 {
377 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
378 _fileFormat, codecInst) == -1)
379 {
380 WEBRTC_TRACE(
381 kTraceWarning,
382 kTraceVoice,
383 _instanceID,
384 "FilePlayerImpl::StartPlayingFile() failed to initialize stream\
385 playout.");
386 return -1;
387 }
388 } else {
389 CodecInst* no_inst = NULL;
390 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
391 _fileFormat, no_inst,
392 startPosition,
393 stopPosition) == -1)
394 {
395 WEBRTC_TRACE(kTraceError, kTraceVoice, _instanceID,
396 "FilePlayerImpl::StartPlayingFile() failed to initialize\
397 stream playout.");
398 return -1;
399 }
400 }
401 SetAudioScaling(volumeScaling);
402
403 if (SetUpAudioDecoder() == -1)
404 {
405 StopPlayingFile();
406 return -1;
407 }
408 return 0;
409}
410
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000411int32_t FilePlayerImpl::StopPlayingFile()
niklase@google.com470e71d2011-07-07 08:21:25 +0000412{
413 memset(&_codec, 0, sizeof(CodecInst));
414 _numberOf10MsPerFrame = 0;
415 _numberOf10MsInDecoder = 0;
416 return _fileModule.StopPlaying();
417}
418
419bool FilePlayerImpl::IsPlayingFile() const
420{
421 return _fileModule.IsPlaying();
422}
423
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000424int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000425{
426 return _fileModule.PlayoutPositionMs(durationMs);
427}
428
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000429int32_t FilePlayerImpl::SetUpAudioDecoder()
niklase@google.com470e71d2011-07-07 08:21:25 +0000430{
431 if ((_fileModule.codec_info(_codec) == -1))
432 {
433 WEBRTC_TRACE(
434 kTraceWarning,
435 kTraceVoice,
436 _instanceID,
437 "FilePlayerImpl::StartPlayingFile() failed to retrieve Codec info\
438 of file data.");
439 return -1;
440 }
441 if( STR_CASE_CMP(_codec.plname, "L16") != 0 &&
442 _audioDecoder.SetDecodeCodec(_codec,AMRFileStorage) == -1)
443 {
444 WEBRTC_TRACE(
445 kTraceWarning,
446 kTraceVoice,
447 _instanceID,
448 "FilePlayerImpl::StartPlayingFile() codec %s not supported",
449 _codec.plname);
450 return -1;
451 }
452 _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100);
453 _numberOf10MsInDecoder = 0;
454 return 0;
455}
456
457#ifdef WEBRTC_MODULE_UTILITY_VIDEO
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000458VideoFilePlayerImpl::VideoFilePlayerImpl(uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +0000459 FileFormats fileFormat)
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000460 : FilePlayerImpl(instanceID, fileFormat),
461 video_decoder_(new VideoCoder(instanceID)),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +0000462 video_codec_info_(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000463 _decodedVideoFrames(0),
464 _encodedData(*new EncodedVideoData()),
465 _frameScaler(*new FrameScaler()),
henrike@webrtc.org105e0712011-12-16 19:53:46 +0000466 _critSec(CriticalSectionWrapper::CreateCriticalSection()),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +0000467 _startTime(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000468 _accumulatedRenderTimeMs(0),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +0000469 _frameLengthMS(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000470 _numberOfFramesRead(0),
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000471 _videoOnly(false) {
472 memset(&video_codec_info_, 0, sizeof(video_codec_info_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000473}
474
475VideoFilePlayerImpl::~VideoFilePlayerImpl()
476{
henrike@webrtc.org105e0712011-12-16 19:53:46 +0000477 delete _critSec;
niklase@google.com470e71d2011-07-07 08:21:25 +0000478 delete &_frameScaler;
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000479 video_decoder_.reset();
niklase@google.com470e71d2011-07-07 08:21:25 +0000480 delete &_encodedData;
481}
482
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000483int32_t VideoFilePlayerImpl::StartPlayingVideoFile(
leozwang@webrtc.org2559cbf2012-02-27 19:18:25 +0000484 const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +0000485 bool loop,
486 bool videoOnly)
487{
488 CriticalSectionScoped lock( _critSec);
489
490 if(_fileModule.StartPlayingVideoFile(fileName, loop, videoOnly,
491 _fileFormat) != 0)
492 {
493 return -1;
494 }
495
496 _decodedVideoFrames = 0;
497 _accumulatedRenderTimeMs = 0;
498 _frameLengthMS = 0;
499 _numberOfFramesRead = 0;
500 _videoOnly = videoOnly;
501
502 // Set up video_codec_info_ according to file,
503 if(SetUpVideoDecoder() != 0)
504 {
505 StopPlayingFile();
506 return -1;
507 }
508 if(!videoOnly)
509 {
510 // Set up _codec according to file,
511 if(SetUpAudioDecoder() != 0)
512 {
513 StopPlayingFile();
514 return -1;
515 }
516 }
517 return 0;
518}
519
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000520int32_t VideoFilePlayerImpl::StopPlayingFile()
niklase@google.com470e71d2011-07-07 08:21:25 +0000521{
522 CriticalSectionScoped lock( _critSec);
523
524 _decodedVideoFrames = 0;
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000525 video_decoder_.reset(new VideoCoder(_instanceID));
niklase@google.com470e71d2011-07-07 08:21:25 +0000526
527 return FilePlayerImpl::StopPlayingFile();
528}
529
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000530int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame,
531 uint32_t outWidth,
532 uint32_t outHeight)
niklase@google.com470e71d2011-07-07 08:21:25 +0000533{
534 CriticalSectionScoped lock( _critSec);
535
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000536 int32_t retVal = GetVideoFromFile(videoFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000537 if(retVal != 0)
538 {
539 return retVal;
540 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000541 if (!videoFrame.IsZeroSize())
niklase@google.com470e71d2011-07-07 08:21:25 +0000542 {
mflodman@webrtc.org1f992802012-01-27 13:42:53 +0000543 retVal = _frameScaler.ResizeFrameIfNeeded(&videoFrame, outWidth,
niklase@google.com470e71d2011-07-07 08:21:25 +0000544 outHeight);
545 }
546 return retVal;
547}
548
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000549int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000550{
551 CriticalSectionScoped lock( _critSec);
552 // No new video data read from file.
553 if(_encodedData.payloadSize == 0)
554 {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000555 videoFrame.ResetSize();
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 return -1;
557 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000558 int32_t retVal = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000559 if(strncmp(video_codec_info_.plName, "I420", 5) == 0)
560 {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000561 int size_y = video_codec_info_.width * video_codec_info_.height;
562 int half_width = (video_codec_info_.width + 1) / 2;
563 int half_height = (video_codec_info_.height + 1) / 2;
564 int size_uv = half_width * half_height;
565
566 // TODO(mikhal): Do we need to align the stride here?
567 const uint8_t* buffer_y = _encodedData.payloadData;
568 const uint8_t* buffer_u = buffer_y + size_y;
569 const uint8_t* buffer_v = buffer_u + size_uv;
570 videoFrame.CreateFrame(size_y, buffer_y,
571 size_uv, buffer_u,
572 size_uv, buffer_v,
573 video_codec_info_.width, video_codec_info_.height,
574 video_codec_info_.height, half_width, half_width);
niklase@google.com470e71d2011-07-07 08:21:25 +0000575 }else
576 {
577 // Set the timestamp manually since there is no timestamp in the file.
578 // Update timestam according to 90 kHz stream.
579 _encodedData.timeStamp += (90000 / video_codec_info_.maxFramerate);
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000580 retVal = video_decoder_->Decode(videoFrame, _encodedData);
niklase@google.com470e71d2011-07-07 08:21:25 +0000581 }
582
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000583 int64_t renderTimeMs = TickTime::MillisecondTimestamp();
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000584 videoFrame.set_render_time_ms(renderTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000585
586 // Indicate that the current frame in the encoded buffer is old/has
587 // already been read.
588 _encodedData.payloadSize = 0;
589 if( retVal == 0)
590 {
591 _decodedVideoFrames++;
592 }
593 return retVal;
594}
595
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000596int32_t VideoFilePlayerImpl::video_codec_info(
niklase@google.com470e71d2011-07-07 08:21:25 +0000597 VideoCodec& videoCodec) const
598{
599 if(video_codec_info_.plName[0] == 0)
600 {
601 return -1;
602 }
603 memcpy(&videoCodec, &video_codec_info_, sizeof(VideoCodec));
604 return 0;
605}
606
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000607int32_t VideoFilePlayerImpl::TimeUntilNextVideoFrame()
niklase@google.com470e71d2011-07-07 08:21:25 +0000608{
609 if(_fileFormat != kFileFormatAviFile)
610 {
611 return -1;
612 }
613 if(!_fileModule.IsPlaying())
614 {
615 return -1;
616 }
617 if(_encodedData.payloadSize <= 0)
618 {
619 // Read next frame from file.
620 CriticalSectionScoped lock( _critSec);
621
622 if(_fileFormat == kFileFormatAviFile)
623 {
624 // Get next video frame
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000625 uint32_t encodedBufferLengthInBytes = _encodedData.bufferSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 if(_fileModule.PlayoutAVIVideoData(
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000627 reinterpret_cast< int8_t*>(_encodedData.payloadData),
niklase@google.com470e71d2011-07-07 08:21:25 +0000628 encodedBufferLengthInBytes) != 0)
629 {
630 WEBRTC_TRACE(
631 kTraceWarning,
632 kTraceVideo,
633 _instanceID,
634 "FilePlayerImpl::TimeUntilNextVideoFrame() error reading\
635 video data");
636 return -1;
637 }
638 _encodedData.payloadSize = encodedBufferLengthInBytes;
639 _encodedData.codec = video_codec_info_.codecType;
640 _numberOfFramesRead++;
641
642 if(_accumulatedRenderTimeMs == 0)
643 {
644 _startTime = TickTime::Now();
645 // This if-statement should only trigger once.
646 _accumulatedRenderTimeMs = 1;
647 } else {
648 // A full seconds worth of frames have been read.
649 if(_numberOfFramesRead % video_codec_info_.maxFramerate == 0)
650 {
651 // Frame rate is in frames per seconds. Frame length is
652 // calculated as an integer division which means it may
653 // be rounded down. Compensate for this every second.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000654 uint32_t rest = 1000%_frameLengthMS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 _accumulatedRenderTimeMs += rest;
656 }
657 _accumulatedRenderTimeMs += _frameLengthMS;
658 }
659 }
660 }
661
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000662 int64_t timeToNextFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000663 if(_videoOnly)
664 {
665 timeToNextFrame = _accumulatedRenderTimeMs -
666 (TickTime::Now() - _startTime).Milliseconds();
667
668 } else {
669 // Synchronize with the audio stream instead of system clock.
670 timeToNextFrame = _accumulatedRenderTimeMs - _decodedLengthInMS;
671 }
672 if(timeToNextFrame < 0)
673 {
674 return 0;
675
676 } else if(timeToNextFrame > 0x0fffffff)
677 {
678 // Wraparound or audio stream has gone to far ahead of the video stream.
679 return -1;
680 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000681 return static_cast<int32_t>(timeToNextFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000682}
683
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000684int32_t VideoFilePlayerImpl::SetUpVideoDecoder()
niklase@google.com470e71d2011-07-07 08:21:25 +0000685{
686 if (_fileModule.VideoCodecInst(video_codec_info_) != 0)
687 {
688 WEBRTC_TRACE(
689 kTraceWarning,
690 kTraceVideo,
691 _instanceID,
692 "FilePlayerImpl::SetVideoDecoder() failed to retrieve Codec info of\
693 file data.");
694 return -1;
695 }
696
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000697 int32_t useNumberOfCores = 1;
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000698 if (video_decoder_->SetDecodeCodec(video_codec_info_, useNumberOfCores) !=
699 0) {
700 WEBRTC_TRACE(kTraceWarning,
701 kTraceVideo,
702 _instanceID,
703 "FilePlayerImpl::SetUpVideoDecoder() codec %s not supported",
704 video_codec_info_.plName);
niklase@google.com470e71d2011-07-07 08:21:25 +0000705 return -1;
706 }
707
niklase@google.com470e71d2011-07-07 08:21:25 +0000708 _frameLengthMS = 1000/video_codec_info_.maxFramerate;
709
710 // Size of unencoded data (I420) should be the largest possible frame size
711 // in a file.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000712 const uint32_t KReadBufferSize = 3 * video_codec_info_.width *
niklase@google.com470e71d2011-07-07 08:21:25 +0000713 video_codec_info_.height / 2;
714 _encodedData.VerifyAndAllocate(KReadBufferSize);
715 _encodedData.encodedHeight = video_codec_info_.height;
716 _encodedData.encodedWidth = video_codec_info_.width;
717 _encodedData.payloadType = video_codec_info_.plType;
718 _encodedData.timeStamp = 0;
719 return 0;
720}
721#endif // WEBRTC_MODULE_UTILITY_VIDEO
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000722} // namespace webrtc