blob: 8049245fb06cb49a35b31d660a744a08f17b94ea [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"
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +000012#include "webrtc/system_wrappers/interface/logging.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
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +000038 assert(false);
niklase@google.com470e71d2011-07-07 08:21:25 +000039 return NULL;
mflodman@webrtc.orgc80d9d92012-02-06 10:11:25 +000040#endif
niklase@google.com470e71d2011-07-07 08:21:25 +000041 }
mflodman@webrtc.org657b2a42012-02-06 11:06:01 +000042 assert(false);
43 return NULL;
niklase@google.com470e71d2011-07-07 08:21:25 +000044}
45
46void FilePlayer::DestroyFilePlayer(FilePlayer* player)
47{
48 delete player;
49}
50
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000051FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +000052 const FileFormats fileFormat)
53 : _instanceID(instanceID),
54 _fileFormat(fileFormat),
55 _fileModule(*MediaFile::CreateMediaFile(instanceID)),
56 _decodedLengthInMS(0),
57 _audioDecoder(instanceID),
58 _codec(),
59 _numberOf10MsPerFrame(0),
60 _numberOf10MsInDecoder(0),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +000061 _resampler(),
niklase@google.com470e71d2011-07-07 08:21:25 +000062 _scaling(1.0)
63{
64 _codec.plfreq = 0;
65}
66
67FilePlayerImpl::~FilePlayerImpl()
68{
69 MediaFile::DestroyMediaFile(&_fileModule);
70}
71
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +000072int32_t FilePlayerImpl::Frequency() const
niklase@google.com470e71d2011-07-07 08:21:25 +000073{
74 if(_codec.plfreq == 0)
75 {
76 return -1;
77 }
78 // Make sure that sample rate is 8,16 or 32 kHz. E.g. WAVE files may have
79 // other sampling rates.
80 if(_codec.plfreq == 11000)
81 {
82 return 16000;
83 }
84 else if(_codec.plfreq == 22000)
85 {
86 return 32000;
87 }
88 else if(_codec.plfreq == 44000)
89 {
90 return 32000;
91 }
92 else if(_codec.plfreq == 48000)
93 {
94 return 32000;
95 }
96 else
97 {
98 return _codec.plfreq;
99 }
100}
101
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000102int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const
niklase@google.com470e71d2011-07-07 08:21:25 +0000103{
104 audioCodec = _codec;
105 return 0;
106}
107
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000108int32_t FilePlayerImpl::Get10msAudioFromFile(
andrew@webrtc.orge59a0ac2012-05-08 17:12:40 +0000109 int16_t* outBuffer,
110 int& lengthInSamples,
111 int frequencyInHz)
niklase@google.com470e71d2011-07-07 08:21:25 +0000112{
113 if(_codec.plfreq == 0)
114 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000115 LOG(LS_WARNING) << "Get10msAudioFromFile() playing not started!"
116 << " codec freq = " << _codec.plfreq
117 << ", wanted freq = " << frequencyInHz;
niklase@google.com470e71d2011-07-07 08:21:25 +0000118 return -1;
119 }
120
121 AudioFrame unresampledAudioFrame;
122 if(STR_CASE_CMP(_codec.plname, "L16") == 0)
123 {
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000124 unresampledAudioFrame.sample_rate_hz_ = _codec.plfreq;
niklase@google.com470e71d2011-07-07 08:21:25 +0000125
126 // L16 is un-encoded data. Just pull 10 ms.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000127 uint32_t lengthInBytes =
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000128 sizeof(unresampledAudioFrame.data_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000129 if (_fileModule.PlayoutAudioData(
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000130 (int8_t*)unresampledAudioFrame.data_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000131 lengthInBytes) == -1)
132 {
133 // End of file reached.
134 return -1;
135 }
136 if(lengthInBytes == 0)
137 {
138 lengthInSamples = 0;
139 return 0;
140 }
141 // One sample is two bytes.
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000142 unresampledAudioFrame.samples_per_channel_ =
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000143 (uint16_t)lengthInBytes >> 1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000144
145 }else {
146 // Decode will generate 10 ms of audio data. PlayoutAudioData(..)
147 // expects a full frame. If the frame size is larger than 10 ms,
148 // PlayoutAudioData(..) data should be called proportionally less often.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000149 int16_t encodedBuffer[MAX_AUDIO_BUFFER_IN_SAMPLES];
150 uint32_t encodedLengthInBytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 if(++_numberOf10MsInDecoder >= _numberOf10MsPerFrame)
152 {
153 _numberOf10MsInDecoder = 0;
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000154 uint32_t bytesFromFile = sizeof(encodedBuffer);
155 if (_fileModule.PlayoutAudioData((int8_t*)encodedBuffer,
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 bytesFromFile) == -1)
157 {
158 // End of file reached.
159 return -1;
160 }
161 encodedLengthInBytes = bytesFromFile;
162 }
163 if(_audioDecoder.Decode(unresampledAudioFrame,frequencyInHz,
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000164 (int8_t*)encodedBuffer,
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 encodedLengthInBytes) == -1)
166 {
167 return -1;
168 }
169 }
170
171 int outLen = 0;
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000172 if(_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000173 frequencyInHz, kResamplerSynchronous))
174 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000175 LOG(LS_WARNING) << "Get10msAudioFromFile() unexpected codec.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000176
177 // New sampling frequency. Update state.
178 outLen = frequencyInHz / 100;
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000179 memset(outBuffer, 0, outLen * sizeof(int16_t));
niklase@google.com470e71d2011-07-07 08:21:25 +0000180 return 0;
181 }
andrew@webrtc.org63a50982012-05-02 23:56:37 +0000182 _resampler.Push(unresampledAudioFrame.data_,
183 unresampledAudioFrame.samples_per_channel_,
niklase@google.com470e71d2011-07-07 08:21:25 +0000184 outBuffer,
185 MAX_AUDIO_BUFFER_IN_SAMPLES,
186 outLen);
187
188 lengthInSamples = outLen;
189
190 if(_scaling != 1.0)
191 {
192 for (int i = 0;i < outLen; i++)
193 {
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000194 outBuffer[i] = (int16_t)(outBuffer[i] * _scaling);
niklase@google.com470e71d2011-07-07 08:21:25 +0000195 }
196 }
197 _decodedLengthInMS += 10;
198 return 0;
199}
200
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000201int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback)
niklase@google.com470e71d2011-07-07 08:21:25 +0000202{
203 return _fileModule.SetModuleFileCallback(callback);
204}
205
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000206int32_t FilePlayerImpl::SetAudioScaling(float scaleFactor)
niklase@google.com470e71d2011-07-07 08:21:25 +0000207{
208 if((scaleFactor >= 0)&&(scaleFactor <= 2.0))
209 {
210 _scaling = scaleFactor;
211 return 0;
212 }
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000213 LOG(LS_WARNING) << "SetAudioScaling() non-allowed scale factor.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000214 return -1;
215}
216
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000217int32_t FilePlayerImpl::StartPlayingFile(const char* fileName,
218 bool loop,
219 uint32_t startPosition,
220 float volumeScaling,
221 uint32_t notification,
222 uint32_t stopPosition,
223 const CodecInst* codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000224{
225 if (_fileFormat == kFileFormatPcm16kHzFile ||
226 _fileFormat == kFileFormatPcm8kHzFile||
227 _fileFormat == kFileFormatPcm32kHzFile )
228 {
229 CodecInst codecInstL16;
230 strncpy(codecInstL16.plname,"L16",32);
231 codecInstL16.pltype = 93;
232 codecInstL16.channels = 1;
233
234 if (_fileFormat == kFileFormatPcm8kHzFile)
235 {
236 codecInstL16.rate = 128000;
237 codecInstL16.plfreq = 8000;
238 codecInstL16.pacsize = 80;
239
240 } else if(_fileFormat == kFileFormatPcm16kHzFile)
241 {
242 codecInstL16.rate = 256000;
243 codecInstL16.plfreq = 16000;
244 codecInstL16.pacsize = 160;
245
246 }else if(_fileFormat == kFileFormatPcm32kHzFile)
247 {
248 codecInstL16.rate = 512000;
249 codecInstL16.plfreq = 32000;
250 codecInstL16.pacsize = 160;
251 } else
252 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000253 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
254 << "supported for PCM format.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000255 return -1;
256 }
257
258 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
259 _fileFormat, &codecInstL16,
260 startPosition,
261 stopPosition) == -1)
262 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000263 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
264 << "pcm file " << fileName;
niklase@google.com470e71d2011-07-07 08:21:25 +0000265 return -1;
266 }
267 SetAudioScaling(volumeScaling);
268 }else if(_fileFormat == kFileFormatPreencodedFile)
269 {
270 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
271 _fileFormat, codecInst) == -1)
272 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000273 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
274 << "pre-encoded file " << fileName;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275 return -1;
276 }
277 } else
278 {
279 CodecInst* no_inst = NULL;
280 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
281 _fileFormat, no_inst,
282 startPosition,
283 stopPosition) == -1)
284 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000285 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize file "
286 << fileName;
niklase@google.com470e71d2011-07-07 08:21:25 +0000287 return -1;
288 }
289 SetAudioScaling(volumeScaling);
290 }
291 if (SetUpAudioDecoder() == -1)
292 {
293 StopPlayingFile();
294 return -1;
295 }
296 return 0;
297}
298
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000299int32_t FilePlayerImpl::StartPlayingFile(InStream& sourceStream,
300 uint32_t startPosition,
301 float volumeScaling,
302 uint32_t notification,
303 uint32_t stopPosition,
304 const CodecInst* codecInst)
niklase@google.com470e71d2011-07-07 08:21:25 +0000305{
306 if (_fileFormat == kFileFormatPcm16kHzFile ||
307 _fileFormat == kFileFormatPcm32kHzFile ||
308 _fileFormat == kFileFormatPcm8kHzFile)
309 {
310 CodecInst codecInstL16;
311 strncpy(codecInstL16.plname,"L16",32);
312 codecInstL16.pltype = 93;
313 codecInstL16.channels = 1;
314
315 if (_fileFormat == kFileFormatPcm8kHzFile)
316 {
317 codecInstL16.rate = 128000;
318 codecInstL16.plfreq = 8000;
319 codecInstL16.pacsize = 80;
320
321 }else if (_fileFormat == kFileFormatPcm16kHzFile)
322 {
323 codecInstL16.rate = 256000;
324 codecInstL16.plfreq = 16000;
325 codecInstL16.pacsize = 160;
326
327 }else if (_fileFormat == kFileFormatPcm32kHzFile)
328 {
329 codecInstL16.rate = 512000;
330 codecInstL16.plfreq = 32000;
331 codecInstL16.pacsize = 160;
332 }else
333 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000334 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
335 << "supported for PCM format.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000336 return -1;
337 }
338 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
339 _fileFormat, &codecInstL16,
340 startPosition,
341 stopPosition) == -1)
342 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000343 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
344 << "playout.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000345 return -1;
346 }
347
348 }else if(_fileFormat == kFileFormatPreencodedFile)
349 {
350 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
351 _fileFormat, codecInst) == -1)
352 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000353 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
354 << "playout.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000355 return -1;
356 }
357 } else {
358 CodecInst* no_inst = NULL;
359 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
360 _fileFormat, no_inst,
361 startPosition,
362 stopPosition) == -1)
363 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000364 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
365 << "playout.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000366 return -1;
367 }
368 }
369 SetAudioScaling(volumeScaling);
370
371 if (SetUpAudioDecoder() == -1)
372 {
373 StopPlayingFile();
374 return -1;
375 }
376 return 0;
377}
378
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000379int32_t FilePlayerImpl::StopPlayingFile()
niklase@google.com470e71d2011-07-07 08:21:25 +0000380{
381 memset(&_codec, 0, sizeof(CodecInst));
382 _numberOf10MsPerFrame = 0;
383 _numberOf10MsInDecoder = 0;
384 return _fileModule.StopPlaying();
385}
386
387bool FilePlayerImpl::IsPlayingFile() const
388{
389 return _fileModule.IsPlaying();
390}
391
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000392int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs)
niklase@google.com470e71d2011-07-07 08:21:25 +0000393{
394 return _fileModule.PlayoutPositionMs(durationMs);
395}
396
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000397int32_t FilePlayerImpl::SetUpAudioDecoder()
niklase@google.com470e71d2011-07-07 08:21:25 +0000398{
399 if ((_fileModule.codec_info(_codec) == -1))
400 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000401 LOG(LS_WARNING) << "Failed to retrieve codec info of file data.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000402 return -1;
403 }
404 if( STR_CASE_CMP(_codec.plname, "L16") != 0 &&
405 _audioDecoder.SetDecodeCodec(_codec,AMRFileStorage) == -1)
406 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000407 LOG(LS_WARNING) << "SetUpAudioDecoder() codec " << _codec.plname
408 << " not supported.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000409 return -1;
410 }
411 _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100);
412 _numberOf10MsInDecoder = 0;
413 return 0;
414}
415
416#ifdef WEBRTC_MODULE_UTILITY_VIDEO
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000417VideoFilePlayerImpl::VideoFilePlayerImpl(uint32_t instanceID,
niklase@google.com470e71d2011-07-07 08:21:25 +0000418 FileFormats fileFormat)
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000419 : FilePlayerImpl(instanceID, fileFormat),
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000420 video_decoder_(new VideoCoder()),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +0000421 video_codec_info_(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000422 _decodedVideoFrames(0),
423 _encodedData(*new EncodedVideoData()),
424 _frameScaler(*new FrameScaler()),
henrike@webrtc.org105e0712011-12-16 19:53:46 +0000425 _critSec(CriticalSectionWrapper::CreateCriticalSection()),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +0000426 _startTime(),
niklase@google.com470e71d2011-07-07 08:21:25 +0000427 _accumulatedRenderTimeMs(0),
henrike@webrtc.org6b9253e2012-02-15 18:48:16 +0000428 _frameLengthMS(0),
niklase@google.com470e71d2011-07-07 08:21:25 +0000429 _numberOfFramesRead(0),
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000430 _videoOnly(false) {
431 memset(&video_codec_info_, 0, sizeof(video_codec_info_));
niklase@google.com470e71d2011-07-07 08:21:25 +0000432}
433
434VideoFilePlayerImpl::~VideoFilePlayerImpl()
435{
henrike@webrtc.org105e0712011-12-16 19:53:46 +0000436 delete _critSec;
niklase@google.com470e71d2011-07-07 08:21:25 +0000437 delete &_frameScaler;
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000438 video_decoder_.reset();
niklase@google.com470e71d2011-07-07 08:21:25 +0000439 delete &_encodedData;
440}
441
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000442int32_t VideoFilePlayerImpl::StartPlayingVideoFile(
leozwang@webrtc.org2559cbf2012-02-27 19:18:25 +0000443 const char* fileName,
niklase@google.com470e71d2011-07-07 08:21:25 +0000444 bool loop,
445 bool videoOnly)
446{
447 CriticalSectionScoped lock( _critSec);
448
449 if(_fileModule.StartPlayingVideoFile(fileName, loop, videoOnly,
450 _fileFormat) != 0)
451 {
452 return -1;
453 }
454
455 _decodedVideoFrames = 0;
456 _accumulatedRenderTimeMs = 0;
457 _frameLengthMS = 0;
458 _numberOfFramesRead = 0;
459 _videoOnly = videoOnly;
460
461 // Set up video_codec_info_ according to file,
462 if(SetUpVideoDecoder() != 0)
463 {
464 StopPlayingFile();
465 return -1;
466 }
467 if(!videoOnly)
468 {
469 // Set up _codec according to file,
470 if(SetUpAudioDecoder() != 0)
471 {
472 StopPlayingFile();
473 return -1;
474 }
475 }
476 return 0;
477}
478
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000479int32_t VideoFilePlayerImpl::StopPlayingFile()
niklase@google.com470e71d2011-07-07 08:21:25 +0000480{
481 CriticalSectionScoped lock( _critSec);
482
483 _decodedVideoFrames = 0;
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000484 video_decoder_.reset(new VideoCoder());
niklase@google.com470e71d2011-07-07 08:21:25 +0000485
486 return FilePlayerImpl::StopPlayingFile();
487}
488
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000489int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame,
490 uint32_t outWidth,
491 uint32_t outHeight)
niklase@google.com470e71d2011-07-07 08:21:25 +0000492{
493 CriticalSectionScoped lock( _critSec);
494
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000495 int32_t retVal = GetVideoFromFile(videoFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000496 if(retVal != 0)
497 {
498 return retVal;
499 }
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000500 if (!videoFrame.IsZeroSize())
niklase@google.com470e71d2011-07-07 08:21:25 +0000501 {
mflodman@webrtc.org1f992802012-01-27 13:42:53 +0000502 retVal = _frameScaler.ResizeFrameIfNeeded(&videoFrame, outWidth,
niklase@google.com470e71d2011-07-07 08:21:25 +0000503 outHeight);
504 }
505 return retVal;
506}
507
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000508int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame)
niklase@google.com470e71d2011-07-07 08:21:25 +0000509{
510 CriticalSectionScoped lock( _critSec);
511 // No new video data read from file.
512 if(_encodedData.payloadSize == 0)
513 {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000514 videoFrame.ResetSize();
niklase@google.com470e71d2011-07-07 08:21:25 +0000515 return -1;
516 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000517 int32_t retVal = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000518 if(strncmp(video_codec_info_.plName, "I420", 5) == 0)
519 {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000520 int size_y = video_codec_info_.width * video_codec_info_.height;
521 int half_width = (video_codec_info_.width + 1) / 2;
522 int half_height = (video_codec_info_.height + 1) / 2;
523 int size_uv = half_width * half_height;
524
525 // TODO(mikhal): Do we need to align the stride here?
526 const uint8_t* buffer_y = _encodedData.payloadData;
527 const uint8_t* buffer_u = buffer_y + size_y;
528 const uint8_t* buffer_v = buffer_u + size_uv;
529 videoFrame.CreateFrame(size_y, buffer_y,
530 size_uv, buffer_u,
531 size_uv, buffer_v,
532 video_codec_info_.width, video_codec_info_.height,
533 video_codec_info_.height, half_width, half_width);
niklase@google.com470e71d2011-07-07 08:21:25 +0000534 }else
535 {
536 // Set the timestamp manually since there is no timestamp in the file.
537 // Update timestam according to 90 kHz stream.
538 _encodedData.timeStamp += (90000 / video_codec_info_.maxFramerate);
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000539 retVal = video_decoder_->Decode(videoFrame, _encodedData);
niklase@google.com470e71d2011-07-07 08:21:25 +0000540 }
541
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000542 int64_t renderTimeMs = TickTime::MillisecondTimestamp();
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000543 videoFrame.set_render_time_ms(renderTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000544
545 // Indicate that the current frame in the encoded buffer is old/has
546 // already been read.
547 _encodedData.payloadSize = 0;
548 if( retVal == 0)
549 {
550 _decodedVideoFrames++;
551 }
552 return retVal;
553}
554
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000555int32_t VideoFilePlayerImpl::video_codec_info(
niklase@google.com470e71d2011-07-07 08:21:25 +0000556 VideoCodec& videoCodec) const
557{
558 if(video_codec_info_.plName[0] == 0)
559 {
560 return -1;
561 }
562 memcpy(&videoCodec, &video_codec_info_, sizeof(VideoCodec));
563 return 0;
564}
565
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000566int32_t VideoFilePlayerImpl::TimeUntilNextVideoFrame()
niklase@google.com470e71d2011-07-07 08:21:25 +0000567{
568 if(_fileFormat != kFileFormatAviFile)
569 {
570 return -1;
571 }
572 if(!_fileModule.IsPlaying())
573 {
574 return -1;
575 }
576 if(_encodedData.payloadSize <= 0)
577 {
578 // Read next frame from file.
579 CriticalSectionScoped lock( _critSec);
580
581 if(_fileFormat == kFileFormatAviFile)
582 {
583 // Get next video frame
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000584 uint32_t encodedBufferLengthInBytes = _encodedData.bufferSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000585 if(_fileModule.PlayoutAVIVideoData(
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000586 reinterpret_cast< int8_t*>(_encodedData.payloadData),
niklase@google.com470e71d2011-07-07 08:21:25 +0000587 encodedBufferLengthInBytes) != 0)
588 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000589 LOG(LS_WARNING) << "Error reading video data.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000590 return -1;
591 }
592 _encodedData.payloadSize = encodedBufferLengthInBytes;
593 _encodedData.codec = video_codec_info_.codecType;
594 _numberOfFramesRead++;
595
596 if(_accumulatedRenderTimeMs == 0)
597 {
598 _startTime = TickTime::Now();
599 // This if-statement should only trigger once.
600 _accumulatedRenderTimeMs = 1;
601 } else {
602 // A full seconds worth of frames have been read.
603 if(_numberOfFramesRead % video_codec_info_.maxFramerate == 0)
604 {
605 // Frame rate is in frames per seconds. Frame length is
606 // calculated as an integer division which means it may
607 // be rounded down. Compensate for this every second.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000608 uint32_t rest = 1000%_frameLengthMS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000609 _accumulatedRenderTimeMs += rest;
610 }
611 _accumulatedRenderTimeMs += _frameLengthMS;
612 }
613 }
614 }
615
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000616 int64_t timeToNextFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000617 if(_videoOnly)
618 {
619 timeToNextFrame = _accumulatedRenderTimeMs -
620 (TickTime::Now() - _startTime).Milliseconds();
621
622 } else {
623 // Synchronize with the audio stream instead of system clock.
624 timeToNextFrame = _accumulatedRenderTimeMs - _decodedLengthInMS;
625 }
626 if(timeToNextFrame < 0)
627 {
628 return 0;
629
630 } else if(timeToNextFrame > 0x0fffffff)
631 {
632 // Wraparound or audio stream has gone to far ahead of the video stream.
633 return -1;
634 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000635 return static_cast<int32_t>(timeToNextFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000636}
637
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000638int32_t VideoFilePlayerImpl::SetUpVideoDecoder()
niklase@google.com470e71d2011-07-07 08:21:25 +0000639{
640 if (_fileModule.VideoCodecInst(video_codec_info_) != 0)
641 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000642 LOG(LS_WARNING) << "SetVideoDecoder() failed to retrieve codec info of "
643 << "file data.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000644 return -1;
645 }
646
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000647 int32_t useNumberOfCores = 1;
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000648 if (video_decoder_->SetDecodeCodec(video_codec_info_, useNumberOfCores) !=
649 0) {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000650 LOG(LS_WARNING) << "SetUpVideoDecoder() codec "
651 << video_codec_info_.plName << " not supported.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000652 return -1;
653 }
654
niklase@google.com470e71d2011-07-07 08:21:25 +0000655 _frameLengthMS = 1000/video_codec_info_.maxFramerate;
656
657 // Size of unencoded data (I420) should be the largest possible frame size
658 // in a file.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000659 const uint32_t KReadBufferSize = 3 * video_codec_info_.width *
niklase@google.com470e71d2011-07-07 08:21:25 +0000660 video_codec_info_.height / 2;
661 _encodedData.VerifyAndAllocate(KReadBufferSize);
662 _encodedData.encodedHeight = video_codec_info_.height;
663 _encodedData.encodedWidth = video_codec_info_.width;
664 _encodedData.payloadType = video_codec_info_.plType;
665 _encodedData.timeStamp = 0;
666 return 0;
667}
668#endif // WEBRTC_MODULE_UTILITY_VIDEO
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000669} // namespace webrtc