blob: 1a2b67498a43caf3897da3bee8172c60a2b8c3d1 [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)
460 : FilePlayerImpl(instanceID,fileFormat),
461 _videoDecoder(*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),
471 _videoOnly(false)
472{
473 memset(&video_codec_info_, 0, sizeof(video_codec_info_));
474}
475
476VideoFilePlayerImpl::~VideoFilePlayerImpl()
477{
henrike@webrtc.org105e0712011-12-16 19:53:46 +0000478 delete _critSec;
niklase@google.com470e71d2011-07-07 08:21:25 +0000479 delete &_frameScaler;
480 delete &_videoDecoder;
481 delete &_encodedData;
482}
483
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000484int32_t VideoFilePlayerImpl::StartPlayingVideoFile(
leozwang@webrtc.org2559cbf2012-02-27 19:18:25 +0000485 const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +0000486 bool loop,
487 bool videoOnly)
488{
489 CriticalSectionScoped lock( _critSec);
490
491 if(_fileModule.StartPlayingVideoFile(fileName, loop, videoOnly,
492 _fileFormat) != 0)
493 {
494 return -1;
495 }
496
497 _decodedVideoFrames = 0;
498 _accumulatedRenderTimeMs = 0;
499 _frameLengthMS = 0;
500 _numberOfFramesRead = 0;
501 _videoOnly = videoOnly;
502
503 // Set up video_codec_info_ according to file,
504 if(SetUpVideoDecoder() != 0)
505 {
506 StopPlayingFile();
507 return -1;
508 }
509 if(!videoOnly)
510 {
511 // Set up _codec according to file,
512 if(SetUpAudioDecoder() != 0)
513 {
514 StopPlayingFile();
515 return -1;
516 }
517 }
518 return 0;
519}
520
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000521int32_t VideoFilePlayerImpl::StopPlayingFile()
niklase@google.com470e71d2011-07-07 08:21:25 +0000522{
523 CriticalSectionScoped lock( _critSec);
524
525 _decodedVideoFrames = 0;
pwestin@webrtc.org52fd98d2012-02-13 09:03:53 +0000526 _videoDecoder.ResetDecoder();
niklase@google.com470e71d2011-07-07 08:21:25 +0000527
528 return FilePlayerImpl::StopPlayingFile();
529}
530
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000531int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame,
532 uint32_t outWidth,
533 uint32_t outHeight)
niklase@google.com470e71d2011-07-07 08:21:25 +0000534{
535 CriticalSectionScoped lock( _critSec);
536
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000537 int32_t retVal = GetVideoFromFile(videoFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000538 if(retVal != 0)
539 {
540 return retVal;
541 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000542 if (!videoFrame.IsZeroSize())
niklase@google.com470e71d2011-07-07 08:21:25 +0000543 {
mflodman@webrtc.org1f992802012-01-27 13:42:53 +0000544 retVal = _frameScaler.ResizeFrameIfNeeded(&videoFrame, outWidth,
niklase@google.com470e71d2011-07-07 08:21:25 +0000545 outHeight);
546 }
547 return retVal;
548}
549
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000550int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000551{
552 CriticalSectionScoped lock( _critSec);
553 // No new video data read from file.
554 if(_encodedData.payloadSize == 0)
555 {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000556 videoFrame.ResetSize();
niklase@google.com470e71d2011-07-07 08:21:25 +0000557 return -1;
558 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000559 int32_t retVal = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000560 if(strncmp(video_codec_info_.plName, "I420", 5) == 0)
561 {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000562 int size_y = video_codec_info_.width * video_codec_info_.height;
563 int half_width = (video_codec_info_.width + 1) / 2;
564 int half_height = (video_codec_info_.height + 1) / 2;
565 int size_uv = half_width * half_height;
566
567 // TODO(mikhal): Do we need to align the stride here?
568 const uint8_t* buffer_y = _encodedData.payloadData;
569 const uint8_t* buffer_u = buffer_y + size_y;
570 const uint8_t* buffer_v = buffer_u + size_uv;
571 videoFrame.CreateFrame(size_y, buffer_y,
572 size_uv, buffer_u,
573 size_uv, buffer_v,
574 video_codec_info_.width, video_codec_info_.height,
575 video_codec_info_.height, half_width, half_width);
niklase@google.com470e71d2011-07-07 08:21:25 +0000576 }else
577 {
578 // Set the timestamp manually since there is no timestamp in the file.
579 // Update timestam according to 90 kHz stream.
580 _encodedData.timeStamp += (90000 / video_codec_info_.maxFramerate);
581 retVal = _videoDecoder.Decode(videoFrame, _encodedData);
582 }
583
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000584 int64_t renderTimeMs = TickTime::MillisecondTimestamp();
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000585 videoFrame.set_render_time_ms(renderTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000586
587 // Indicate that the current frame in the encoded buffer is old/has
588 // already been read.
589 _encodedData.payloadSize = 0;
590 if( retVal == 0)
591 {
592 _decodedVideoFrames++;
593 }
594 return retVal;
595}
596
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000597int32_t VideoFilePlayerImpl::video_codec_info(
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 VideoCodec& videoCodec) const
599{
600 if(video_codec_info_.plName[0] == 0)
601 {
602 return -1;
603 }
604 memcpy(&videoCodec, &video_codec_info_, sizeof(VideoCodec));
605 return 0;
606}
607
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000608int32_t VideoFilePlayerImpl::TimeUntilNextVideoFrame()
niklase@google.com470e71d2011-07-07 08:21:25 +0000609{
610 if(_fileFormat != kFileFormatAviFile)
611 {
612 return -1;
613 }
614 if(!_fileModule.IsPlaying())
615 {
616 return -1;
617 }
618 if(_encodedData.payloadSize <= 0)
619 {
620 // Read next frame from file.
621 CriticalSectionScoped lock( _critSec);
622
623 if(_fileFormat == kFileFormatAviFile)
624 {
625 // Get next video frame
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000626 uint32_t encodedBufferLengthInBytes = _encodedData.bufferSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000627 if(_fileModule.PlayoutAVIVideoData(
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000628 reinterpret_cast< int8_t*>(_encodedData.payloadData),
niklase@google.com470e71d2011-07-07 08:21:25 +0000629 encodedBufferLengthInBytes) != 0)
630 {
631 WEBRTC_TRACE(
632 kTraceWarning,
633 kTraceVideo,
634 _instanceID,
635 "FilePlayerImpl::TimeUntilNextVideoFrame() error reading\
636 video data");
637 return -1;
638 }
639 _encodedData.payloadSize = encodedBufferLengthInBytes;
640 _encodedData.codec = video_codec_info_.codecType;
641 _numberOfFramesRead++;
642
643 if(_accumulatedRenderTimeMs == 0)
644 {
645 _startTime = TickTime::Now();
646 // This if-statement should only trigger once.
647 _accumulatedRenderTimeMs = 1;
648 } else {
649 // A full seconds worth of frames have been read.
650 if(_numberOfFramesRead % video_codec_info_.maxFramerate == 0)
651 {
652 // Frame rate is in frames per seconds. Frame length is
653 // calculated as an integer division which means it may
654 // be rounded down. Compensate for this every second.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000655 uint32_t rest = 1000%_frameLengthMS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 _accumulatedRenderTimeMs += rest;
657 }
658 _accumulatedRenderTimeMs += _frameLengthMS;
659 }
660 }
661 }
662
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000663 int64_t timeToNextFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 if(_videoOnly)
665 {
666 timeToNextFrame = _accumulatedRenderTimeMs -
667 (TickTime::Now() - _startTime).Milliseconds();
668
669 } else {
670 // Synchronize with the audio stream instead of system clock.
671 timeToNextFrame = _accumulatedRenderTimeMs - _decodedLengthInMS;
672 }
673 if(timeToNextFrame < 0)
674 {
675 return 0;
676
677 } else if(timeToNextFrame > 0x0fffffff)
678 {
679 // Wraparound or audio stream has gone to far ahead of the video stream.
680 return -1;
681 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000682 return static_cast<int32_t>(timeToNextFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000683}
684
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000685int32_t VideoFilePlayerImpl::SetUpVideoDecoder()
niklase@google.com470e71d2011-07-07 08:21:25 +0000686{
687 if (_fileModule.VideoCodecInst(video_codec_info_) != 0)
688 {
689 WEBRTC_TRACE(
690 kTraceWarning,
691 kTraceVideo,
692 _instanceID,
693 "FilePlayerImpl::SetVideoDecoder() failed to retrieve Codec info of\
694 file data.");
695 return -1;
696 }
697
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000698 int32_t useNumberOfCores = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000699 if(_videoDecoder.SetDecodeCodec(video_codec_info_, useNumberOfCores) != 0)
700 {
701 WEBRTC_TRACE(
702 kTraceWarning,
703 kTraceVideo,
704 _instanceID,
705 "FilePlayerImpl::SetUpVideoDecoder() codec %s not supported",
706 video_codec_info_.plName);
707 return -1;
708 }
709
niklase@google.com470e71d2011-07-07 08:21:25 +0000710 _frameLengthMS = 1000/video_codec_info_.maxFramerate;
711
712 // Size of unencoded data (I420) should be the largest possible frame size
713 // in a file.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000714 const uint32_t KReadBufferSize = 3 * video_codec_info_.width *
niklase@google.com470e71d2011-07-07 08:21:25 +0000715 video_codec_info_.height / 2;
716 _encodedData.VerifyAndAllocate(KReadBufferSize);
717 _encodedData.encodedHeight = video_codec_info_.height;
718 _encodedData.encodedWidth = video_codec_info_.width;
719 _encodedData.payloadType = video_codec_info_.plType;
720 _encodedData.timeStamp = 0;
721 return 0;
722}
723#endif // WEBRTC_MODULE_UTILITY_VIDEO
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000724} // namespace webrtc