blob: 3a06c72dae03ac32e4911a09805c82d6c9cd3968 [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
11#include "file_player_impl.h"
12#include "trace.h"
13
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
20// OS independent case insensitive string comparison.
21#ifdef WIN32
22 #define STR_CASE_CMP(x,y) ::_stricmp(x,y)
23#else
24 #define STR_CASE_CMP(x,y) ::strcasecmp(x,y)
25#endif
26
27namespace webrtc {
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000028FilePlayer* FilePlayer::CreateFilePlayer(uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +000029 FileFormats fileFormat)
30{
31 switch(fileFormat)
32 {
33 case kFileFormatWavFile:
34 case kFileFormatCompressedFile:
35 case kFileFormatPreencodedFile:
36 case kFileFormatPcm16kHzFile:
37 case kFileFormatPcm8kHzFile:
38 case kFileFormatPcm32kHzFile:
39 // audio formats
40 return new FilePlayerImpl(instanceID, fileFormat);
niklase@google.com470e71d2011-07-07 08:21:25 +000041 case kFileFormatAviFile:
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +000042#ifdef WEBRTC_MODULE_UTILITY_VIDEO
niklase@google.com470e71d2011-07-07 08:21:25 +000043 return new VideoFilePlayerImpl(instanceID, fileFormat);
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +000044#else
45 WEBRTC_TRACE(kTraceError, kTraceFile, -1,
46 "Invalid file format: %d", kFileFormatAviFile);
47 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +000048 return NULL;
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +000049#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000050 }
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000051 assert(false);
52 return NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000053}
54
55void FilePlayer::DestroyFilePlayer(FilePlayer* player)
56{
57 delete player;
58}
59
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000060FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +000061 const FileFormats fileFormat)
62 : _instanceID(instanceID),
63 _fileFormat(fileFormat),
64 _fileModule(*MediaFile::CreateMediaFile(instanceID)),
65 _decodedLengthInMS(0),
66 _audioDecoder(instanceID),
67 _codec(),
68 _numberOf10MsPerFrame(0),
69 _numberOf10MsInDecoder(0),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +000070 _resampler(),
niklase@google.com470e71d2011-07-07 08:21:25 +000071 _scaling(1.0)
72{
73 _codec.plfreq = 0;
74}
75
76FilePlayerImpl::~FilePlayerImpl()
77{
78 MediaFile::DestroyMediaFile(&_fileModule);
79}
80
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000081int32_t FilePlayerImpl::Frequency() const
niklase@google.com470e71d2011-07-07 08:21:25 +000082{
83 if(_codec.plfreq == 0)
84 {
85 return -1;
86 }
87 // Make sure that sample rate is 8,16 or 32 kHz. E.g. WAVE files may have
88 // other sampling rates.
89 if(_codec.plfreq == 11000)
90 {
91 return 16000;
92 }
93 else if(_codec.plfreq == 22000)
94 {
95 return 32000;
96 }
97 else if(_codec.plfreq == 44000)
98 {
99 return 32000;
100 }
101 else if(_codec.plfreq == 48000)
102 {
103 return 32000;
104 }
105 else
106 {
107 return _codec.plfreq;
108 }
109}
110
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000111int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000112{
113 audioCodec = _codec;
114 return 0;
115}
116
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000117int32_t FilePlayerImpl::Get10msAudioFromFile(
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +0000118 int16_t* outBuffer,
119 int& lengthInSamples,
120 int frequencyInHz)
niklase@google.com470e71d2011-07-07 08:21:25 +0000121{
122 if(_codec.plfreq == 0)
123 {
124 WEBRTC_TRACE(kTraceWarning, kTraceVoice, _instanceID,
125 "FilePlayerImpl::Get10msAudioFromFile() playing not started!\
126 codecFreq = %d, wantedFreq = %d",
127 _codec.plfreq, frequencyInHz);
128 return -1;
129 }
130
131 AudioFrame unresampledAudioFrame;
132 if(STR_CASE_CMP(_codec.plname, "L16") == 0)
133 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000134 unresampledAudioFrame.sample_rate_hz_ = _codec.plfreq;
niklase@google.com470e71d2011-07-07 08:21:25 +0000135
136 // L16 is un-encoded data. Just pull 10 ms.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000137 uint32_t lengthInBytes =
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000138 sizeof(unresampledAudioFrame.data_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000139 if (_fileModule.PlayoutAudioData(
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000140 (int8_t*)unresampledAudioFrame.data_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000141 lengthInBytes) == -1)
142 {
143 // End of file reached.
144 return -1;
145 }
146 if(lengthInBytes == 0)
147 {
148 lengthInSamples = 0;
149 return 0;
150 }
151 // One sample is two bytes.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000152 unresampledAudioFrame.samples_per_channel_ =
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000153 (uint16_t)lengthInBytes >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000154
155 }else {
156 // Decode will generate 10 ms of audio data. PlayoutAudioData(..)
157 // expects a full frame. If the frame size is larger than 10 ms,
158 // PlayoutAudioData(..) data should be called proportionally less often.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000159 int16_t encodedBuffer[MAX_AUDIO_BUFFER_IN_SAMPLES];
160 uint32_t encodedLengthInBytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000161 if(++_numberOf10MsInDecoder >= _numberOf10MsPerFrame)
162 {
163 _numberOf10MsInDecoder = 0;
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000164 uint32_t bytesFromFile = sizeof(encodedBuffer);
165 if (_fileModule.PlayoutAudioData((int8_t*)encodedBuffer,
niklase@google.com470e71d2011-07-07 08:21:25 +0000166 bytesFromFile) == -1)
167 {
168 // End of file reached.
169 return -1;
170 }
171 encodedLengthInBytes = bytesFromFile;
172 }
173 if(_audioDecoder.Decode(unresampledAudioFrame,frequencyInHz,
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000174 (int8_t*)encodedBuffer,
niklase@google.com470e71d2011-07-07 08:21:25 +0000175 encodedLengthInBytes) == -1)
176 {
177 return -1;
178 }
179 }
180
181 int outLen = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000182 if(_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000183 frequencyInHz, kResamplerSynchronous))
184 {
185 WEBRTC_TRACE(kTraceWarning, kTraceVoice, _instanceID,
186 "FilePlayerImpl::Get10msAudioFromFile() unexpected codec");
187
188 // New sampling frequency. Update state.
189 outLen = frequencyInHz / 100;
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000190 memset(outBuffer, 0, outLen * sizeof(int16_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000191 return 0;
192 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000193 _resampler.Push(unresampledAudioFrame.data_,
194 unresampledAudioFrame.samples_per_channel_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 outBuffer,
196 MAX_AUDIO_BUFFER_IN_SAMPLES,
197 outLen);
198
199 lengthInSamples = outLen;
200
201 if(_scaling != 1.0)
202 {
203 for (int i = 0;i < outLen; i++)
204 {
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000205 outBuffer[i] = (int16_t)(outBuffer[i] * _scaling);
niklase@google.com470e71d2011-07-07 08:21:25 +0000206 }
207 }
208 _decodedLengthInMS += 10;
209 return 0;
210}
211
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000212int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback)
niklase@google.com470e71d2011-07-07 08:21:25 +0000213{
214 return _fileModule.SetModuleFileCallback(callback);
215}
216
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000217int32_t FilePlayerImpl::SetAudioScaling(float scaleFactor)
niklase@google.com470e71d2011-07-07 08:21:25 +0000218{
219 if((scaleFactor >= 0)&&(scaleFactor <= 2.0))
220 {
221 _scaling = scaleFactor;
222 return 0;
223 }
224 WEBRTC_TRACE(kTraceWarning, kTraceVoice, _instanceID,
225 "FilePlayerImpl::SetAudioScaling() not allowed scale factor");
226 return -1;
227}
228
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000229int32_t FilePlayerImpl::StartPlayingFile(const char* fileName,
230 bool loop,
231 uint32_t startPosition,
232 float volumeScaling,
233 uint32_t notification,
234 uint32_t stopPosition,
235 const CodecInst* codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000236{
237 if (_fileFormat == kFileFormatPcm16kHzFile ||
238 _fileFormat == kFileFormatPcm8kHzFile||
239 _fileFormat == kFileFormatPcm32kHzFile )
240 {
241 CodecInst codecInstL16;
242 strncpy(codecInstL16.plname,"L16",32);
243 codecInstL16.pltype = 93;
244 codecInstL16.channels = 1;
245
246 if (_fileFormat == kFileFormatPcm8kHzFile)
247 {
248 codecInstL16.rate = 128000;
249 codecInstL16.plfreq = 8000;
250 codecInstL16.pacsize = 80;
251
252 } else if(_fileFormat == kFileFormatPcm16kHzFile)
253 {
254 codecInstL16.rate = 256000;
255 codecInstL16.plfreq = 16000;
256 codecInstL16.pacsize = 160;
257
258 }else if(_fileFormat == kFileFormatPcm32kHzFile)
259 {
260 codecInstL16.rate = 512000;
261 codecInstL16.plfreq = 32000;
262 codecInstL16.pacsize = 160;
263 } else
264 {
265 WEBRTC_TRACE(kTraceError, kTraceVoice, _instanceID,
266 "FilePlayerImpl::StartPlayingFile() sample frequency\
267 specifed not supported for PCM format.");
268 return -1;
269 }
270
271 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
272 _fileFormat, &codecInstL16,
273 startPosition,
274 stopPosition) == -1)
275 {
276 WEBRTC_TRACE(
277 kTraceWarning,
278 kTraceVoice,
279 _instanceID,
280 "FilePlayerImpl::StartPlayingFile() failed to initialize file\
281 %s playout.", fileName);
282 return -1;
283 }
284 SetAudioScaling(volumeScaling);
285 }else if(_fileFormat == kFileFormatPreencodedFile)
286 {
287 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
288 _fileFormat, codecInst) == -1)
289 {
290 WEBRTC_TRACE(
291 kTraceWarning,
292 kTraceVoice,
293 _instanceID,
294 "FilePlayerImpl::StartPlayingPreEncodedFile() failed to\
295 initialize pre-encoded file %s playout.",
296 fileName);
297 return -1;
298 }
299 } else
300 {
301 CodecInst* no_inst = NULL;
302 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
303 _fileFormat, no_inst,
304 startPosition,
305 stopPosition) == -1)
306 {
307 WEBRTC_TRACE(
308 kTraceWarning,
309 kTraceVoice,
310 _instanceID,
311 "FilePlayerImpl::StartPlayingFile() failed to initialize file\
312 %s playout.", fileName);
313 return -1;
314 }
315 SetAudioScaling(volumeScaling);
316 }
317 if (SetUpAudioDecoder() == -1)
318 {
319 StopPlayingFile();
320 return -1;
321 }
322 return 0;
323}
324
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000325int32_t FilePlayerImpl::StartPlayingFile(InStream& sourceStream,
326 uint32_t startPosition,
327 float volumeScaling,
328 uint32_t notification,
329 uint32_t stopPosition,
330 const CodecInst* codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000331{
332 if (_fileFormat == kFileFormatPcm16kHzFile ||
333 _fileFormat == kFileFormatPcm32kHzFile ||
334 _fileFormat == kFileFormatPcm8kHzFile)
335 {
336 CodecInst codecInstL16;
337 strncpy(codecInstL16.plname,"L16",32);
338 codecInstL16.pltype = 93;
339 codecInstL16.channels = 1;
340
341 if (_fileFormat == kFileFormatPcm8kHzFile)
342 {
343 codecInstL16.rate = 128000;
344 codecInstL16.plfreq = 8000;
345 codecInstL16.pacsize = 80;
346
347 }else if (_fileFormat == kFileFormatPcm16kHzFile)
348 {
349 codecInstL16.rate = 256000;
350 codecInstL16.plfreq = 16000;
351 codecInstL16.pacsize = 160;
352
353 }else if (_fileFormat == kFileFormatPcm32kHzFile)
354 {
355 codecInstL16.rate = 512000;
356 codecInstL16.plfreq = 32000;
357 codecInstL16.pacsize = 160;
358 }else
359 {
360 WEBRTC_TRACE(
361 kTraceError,
362 kTraceVoice,
363 _instanceID,
364 "FilePlayerImpl::StartPlayingFile() sample frequency specifed\
365 not supported for PCM format.");
366 return -1;
367 }
368 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
369 _fileFormat, &codecInstL16,
370 startPosition,
371 stopPosition) == -1)
372 {
373 WEBRTC_TRACE(
374 kTraceError,
375 kTraceVoice,
376 _instanceID,
377 "FilePlayerImpl::StartPlayingFile() failed to initialize stream\
378 playout.");
379 return -1;
380 }
381
382 }else if(_fileFormat == kFileFormatPreencodedFile)
383 {
384 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
385 _fileFormat, codecInst) == -1)
386 {
387 WEBRTC_TRACE(
388 kTraceWarning,
389 kTraceVoice,
390 _instanceID,
391 "FilePlayerImpl::StartPlayingFile() failed to initialize stream\
392 playout.");
393 return -1;
394 }
395 } else {
396 CodecInst* no_inst = NULL;
397 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
398 _fileFormat, no_inst,
399 startPosition,
400 stopPosition) == -1)
401 {
402 WEBRTC_TRACE(kTraceError, kTraceVoice, _instanceID,
403 "FilePlayerImpl::StartPlayingFile() failed to initialize\
404 stream playout.");
405 return -1;
406 }
407 }
408 SetAudioScaling(volumeScaling);
409
410 if (SetUpAudioDecoder() == -1)
411 {
412 StopPlayingFile();
413 return -1;
414 }
415 return 0;
416}
417
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000418int32_t FilePlayerImpl::StopPlayingFile()
niklase@google.com470e71d2011-07-07 08:21:25 +0000419{
420 memset(&_codec, 0, sizeof(CodecInst));
421 _numberOf10MsPerFrame = 0;
422 _numberOf10MsInDecoder = 0;
423 return _fileModule.StopPlaying();
424}
425
426bool FilePlayerImpl::IsPlayingFile() const
427{
428 return _fileModule.IsPlaying();
429}
430
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000431int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000432{
433 return _fileModule.PlayoutPositionMs(durationMs);
434}
435
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000436int32_t FilePlayerImpl::SetUpAudioDecoder()
niklase@google.com470e71d2011-07-07 08:21:25 +0000437{
438 if ((_fileModule.codec_info(_codec) == -1))
439 {
440 WEBRTC_TRACE(
441 kTraceWarning,
442 kTraceVoice,
443 _instanceID,
444 "FilePlayerImpl::StartPlayingFile() failed to retrieve Codec info\
445 of file data.");
446 return -1;
447 }
448 if( STR_CASE_CMP(_codec.plname, "L16") != 0 &&
449 _audioDecoder.SetDecodeCodec(_codec,AMRFileStorage) == -1)
450 {
451 WEBRTC_TRACE(
452 kTraceWarning,
453 kTraceVoice,
454 _instanceID,
455 "FilePlayerImpl::StartPlayingFile() codec %s not supported",
456 _codec.plname);
457 return -1;
458 }
459 _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100);
460 _numberOf10MsInDecoder = 0;
461 return 0;
462}
463
464#ifdef WEBRTC_MODULE_UTILITY_VIDEO
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000465VideoFilePlayerImpl::VideoFilePlayerImpl(uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +0000466 FileFormats fileFormat)
467 : FilePlayerImpl(instanceID,fileFormat),
468 _videoDecoder(*new VideoCoder(instanceID)),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +0000469 video_codec_info_(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000470 _decodedVideoFrames(0),
471 _encodedData(*new EncodedVideoData()),
472 _frameScaler(*new FrameScaler()),
henrike@webrtc.org105e0712011-12-16 19:53:46 +0000473 _critSec(CriticalSectionWrapper::CreateCriticalSection()),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +0000474 _startTime(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000475 _accumulatedRenderTimeMs(0),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +0000476 _frameLengthMS(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000477 _numberOfFramesRead(0),
478 _videoOnly(false)
479{
480 memset(&video_codec_info_, 0, sizeof(video_codec_info_));
481}
482
483VideoFilePlayerImpl::~VideoFilePlayerImpl()
484{
henrike@webrtc.org105e0712011-12-16 19:53:46 +0000485 delete _critSec;
niklase@google.com470e71d2011-07-07 08:21:25 +0000486 delete &_frameScaler;
487 delete &_videoDecoder;
488 delete &_encodedData;
489}
490
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000491int32_t VideoFilePlayerImpl::StartPlayingVideoFile(
leozwang@webrtc.org2559cbf2012-02-27 19:18:25 +0000492 const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +0000493 bool loop,
494 bool videoOnly)
495{
496 CriticalSectionScoped lock( _critSec);
497
498 if(_fileModule.StartPlayingVideoFile(fileName, loop, videoOnly,
499 _fileFormat) != 0)
500 {
501 return -1;
502 }
503
504 _decodedVideoFrames = 0;
505 _accumulatedRenderTimeMs = 0;
506 _frameLengthMS = 0;
507 _numberOfFramesRead = 0;
508 _videoOnly = videoOnly;
509
510 // Set up video_codec_info_ according to file,
511 if(SetUpVideoDecoder() != 0)
512 {
513 StopPlayingFile();
514 return -1;
515 }
516 if(!videoOnly)
517 {
518 // Set up _codec according to file,
519 if(SetUpAudioDecoder() != 0)
520 {
521 StopPlayingFile();
522 return -1;
523 }
524 }
525 return 0;
526}
527
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000528int32_t VideoFilePlayerImpl::StopPlayingFile()
niklase@google.com470e71d2011-07-07 08:21:25 +0000529{
530 CriticalSectionScoped lock( _critSec);
531
532 _decodedVideoFrames = 0;
pwestin@webrtc.org52fd98d2012-02-13 09:03:53 +0000533 _videoDecoder.ResetDecoder();
niklase@google.com470e71d2011-07-07 08:21:25 +0000534
535 return FilePlayerImpl::StopPlayingFile();
536}
537
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000538int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame,
539 uint32_t outWidth,
540 uint32_t outHeight)
niklase@google.com470e71d2011-07-07 08:21:25 +0000541{
542 CriticalSectionScoped lock( _critSec);
543
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000544 int32_t retVal = GetVideoFromFile(videoFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000545 if(retVal != 0)
546 {
547 return retVal;
548 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000549 if (!videoFrame.IsZeroSize())
niklase@google.com470e71d2011-07-07 08:21:25 +0000550 {
mflodman@webrtc.org1f992802012-01-27 13:42:53 +0000551 retVal = _frameScaler.ResizeFrameIfNeeded(&videoFrame, outWidth,
niklase@google.com470e71d2011-07-07 08:21:25 +0000552 outHeight);
553 }
554 return retVal;
555}
556
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000557int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000558{
559 CriticalSectionScoped lock( _critSec);
560 // No new video data read from file.
561 if(_encodedData.payloadSize == 0)
562 {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000563 videoFrame.ResetSize();
niklase@google.com470e71d2011-07-07 08:21:25 +0000564 return -1;
565 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000566 int32_t retVal = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000567 if(strncmp(video_codec_info_.plName, "I420", 5) == 0)
568 {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000569 int size_y = video_codec_info_.width * video_codec_info_.height;
570 int half_width = (video_codec_info_.width + 1) / 2;
571 int half_height = (video_codec_info_.height + 1) / 2;
572 int size_uv = half_width * half_height;
573
574 // TODO(mikhal): Do we need to align the stride here?
575 const uint8_t* buffer_y = _encodedData.payloadData;
576 const uint8_t* buffer_u = buffer_y + size_y;
577 const uint8_t* buffer_v = buffer_u + size_uv;
578 videoFrame.CreateFrame(size_y, buffer_y,
579 size_uv, buffer_u,
580 size_uv, buffer_v,
581 video_codec_info_.width, video_codec_info_.height,
582 video_codec_info_.height, half_width, half_width);
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 }else
584 {
585 // Set the timestamp manually since there is no timestamp in the file.
586 // Update timestam according to 90 kHz stream.
587 _encodedData.timeStamp += (90000 / video_codec_info_.maxFramerate);
588 retVal = _videoDecoder.Decode(videoFrame, _encodedData);
589 }
590
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000591 int64_t renderTimeMs = TickTime::MillisecondTimestamp();
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000592 videoFrame.set_render_time_ms(renderTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000593
594 // Indicate that the current frame in the encoded buffer is old/has
595 // already been read.
596 _encodedData.payloadSize = 0;
597 if( retVal == 0)
598 {
599 _decodedVideoFrames++;
600 }
601 return retVal;
602}
603
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000604int32_t VideoFilePlayerImpl::video_codec_info(
niklase@google.com470e71d2011-07-07 08:21:25 +0000605 VideoCodec& videoCodec) const
606{
607 if(video_codec_info_.plName[0] == 0)
608 {
609 return -1;
610 }
611 memcpy(&videoCodec, &video_codec_info_, sizeof(VideoCodec));
612 return 0;
613}
614
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000615int32_t VideoFilePlayerImpl::TimeUntilNextVideoFrame()
niklase@google.com470e71d2011-07-07 08:21:25 +0000616{
617 if(_fileFormat != kFileFormatAviFile)
618 {
619 return -1;
620 }
621 if(!_fileModule.IsPlaying())
622 {
623 return -1;
624 }
625 if(_encodedData.payloadSize <= 0)
626 {
627 // Read next frame from file.
628 CriticalSectionScoped lock( _critSec);
629
630 if(_fileFormat == kFileFormatAviFile)
631 {
632 // Get next video frame
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000633 uint32_t encodedBufferLengthInBytes = _encodedData.bufferSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000634 if(_fileModule.PlayoutAVIVideoData(
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000635 reinterpret_cast< int8_t*>(_encodedData.payloadData),
niklase@google.com470e71d2011-07-07 08:21:25 +0000636 encodedBufferLengthInBytes) != 0)
637 {
638 WEBRTC_TRACE(
639 kTraceWarning,
640 kTraceVideo,
641 _instanceID,
642 "FilePlayerImpl::TimeUntilNextVideoFrame() error reading\
643 video data");
644 return -1;
645 }
646 _encodedData.payloadSize = encodedBufferLengthInBytes;
647 _encodedData.codec = video_codec_info_.codecType;
648 _numberOfFramesRead++;
649
650 if(_accumulatedRenderTimeMs == 0)
651 {
652 _startTime = TickTime::Now();
653 // This if-statement should only trigger once.
654 _accumulatedRenderTimeMs = 1;
655 } else {
656 // A full seconds worth of frames have been read.
657 if(_numberOfFramesRead % video_codec_info_.maxFramerate == 0)
658 {
659 // Frame rate is in frames per seconds. Frame length is
660 // calculated as an integer division which means it may
661 // be rounded down. Compensate for this every second.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000662 uint32_t rest = 1000%_frameLengthMS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000663 _accumulatedRenderTimeMs += rest;
664 }
665 _accumulatedRenderTimeMs += _frameLengthMS;
666 }
667 }
668 }
669
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000670 int64_t timeToNextFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000671 if(_videoOnly)
672 {
673 timeToNextFrame = _accumulatedRenderTimeMs -
674 (TickTime::Now() - _startTime).Milliseconds();
675
676 } else {
677 // Synchronize with the audio stream instead of system clock.
678 timeToNextFrame = _accumulatedRenderTimeMs - _decodedLengthInMS;
679 }
680 if(timeToNextFrame < 0)
681 {
682 return 0;
683
684 } else if(timeToNextFrame > 0x0fffffff)
685 {
686 // Wraparound or audio stream has gone to far ahead of the video stream.
687 return -1;
688 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000689 return static_cast<int32_t>(timeToNextFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000690}
691
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000692int32_t VideoFilePlayerImpl::SetUpVideoDecoder()
niklase@google.com470e71d2011-07-07 08:21:25 +0000693{
694 if (_fileModule.VideoCodecInst(video_codec_info_) != 0)
695 {
696 WEBRTC_TRACE(
697 kTraceWarning,
698 kTraceVideo,
699 _instanceID,
700 "FilePlayerImpl::SetVideoDecoder() failed to retrieve Codec info of\
701 file data.");
702 return -1;
703 }
704
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000705 int32_t useNumberOfCores = 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000706 if(_videoDecoder.SetDecodeCodec(video_codec_info_, useNumberOfCores) != 0)
707 {
708 WEBRTC_TRACE(
709 kTraceWarning,
710 kTraceVideo,
711 _instanceID,
712 "FilePlayerImpl::SetUpVideoDecoder() codec %s not supported",
713 video_codec_info_.plName);
714 return -1;
715 }
716
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 _frameLengthMS = 1000/video_codec_info_.maxFramerate;
718
719 // Size of unencoded data (I420) should be the largest possible frame size
720 // in a file.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000721 const uint32_t KReadBufferSize = 3 * video_codec_info_.width *
niklase@google.com470e71d2011-07-07 08:21:25 +0000722 video_codec_info_.height / 2;
723 _encodedData.VerifyAndAllocate(KReadBufferSize);
724 _encodedData.encodedHeight = video_codec_info_.height;
725 _encodedData.encodedWidth = video_codec_info_.width;
726 _encodedData.payloadType = video_codec_info_.plType;
727 _encodedData.timeStamp = 0;
728 return 0;
729}
730#endif // WEBRTC_MODULE_UTILITY_VIDEO
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000731} // namespace webrtc