blob: dc30d0a858e467d7930545798730c32ab3d04ce7 [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
andresp@webrtc.org86e1e482015-01-14 09:30:52 +000015 #include "webrtc/modules/utility/source/frame_scaler.h"
16 #include "webrtc/modules/utility/source/video_coder.h"
17 #include "webrtc/system_wrappers/interface/tick_util.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000018#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.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000127 size_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];
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000150 size_t encodedLengthInBytes = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000151 if(++_numberOf10MsInDecoder >= _numberOf10MsPerFrame)
152 {
153 _numberOf10MsInDecoder = 0;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000154 size_t bytesFromFile = sizeof(encodedBuffer);
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000155 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 {
niklase@google.com470e71d2011-07-07 08:21:25 +0000514 return -1;
515 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000516 int32_t retVal = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000517 if(strncmp(video_codec_info_.plName, "I420", 5) == 0)
518 {
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000519 int size_y = video_codec_info_.width * video_codec_info_.height;
520 int half_width = (video_codec_info_.width + 1) / 2;
521 int half_height = (video_codec_info_.height + 1) / 2;
522 int size_uv = half_width * half_height;
523
524 // TODO(mikhal): Do we need to align the stride here?
525 const uint8_t* buffer_y = _encodedData.payloadData;
526 const uint8_t* buffer_u = buffer_y + size_y;
527 const uint8_t* buffer_v = buffer_u + size_uv;
528 videoFrame.CreateFrame(size_y, buffer_y,
529 size_uv, buffer_u,
530 size_uv, buffer_v,
531 video_codec_info_.width, video_codec_info_.height,
532 video_codec_info_.height, half_width, half_width);
niklase@google.com470e71d2011-07-07 08:21:25 +0000533 }else
534 {
535 // Set the timestamp manually since there is no timestamp in the file.
536 // Update timestam according to 90 kHz stream.
537 _encodedData.timeStamp += (90000 / video_codec_info_.maxFramerate);
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000538 retVal = video_decoder_->Decode(videoFrame, _encodedData);
niklase@google.com470e71d2011-07-07 08:21:25 +0000539 }
540
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000541 int64_t renderTimeMs = TickTime::MillisecondTimestamp();
mikhal@webrtc.org9fedff72012-10-24 18:33:04 +0000542 videoFrame.set_render_time_ms(renderTimeMs);
niklase@google.com470e71d2011-07-07 08:21:25 +0000543
544 // Indicate that the current frame in the encoded buffer is old/has
545 // already been read.
546 _encodedData.payloadSize = 0;
547 if( retVal == 0)
548 {
549 _decodedVideoFrames++;
550 }
551 return retVal;
552}
553
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000554int32_t VideoFilePlayerImpl::video_codec_info(
niklase@google.com470e71d2011-07-07 08:21:25 +0000555 VideoCodec& videoCodec) const
556{
557 if(video_codec_info_.plName[0] == 0)
558 {
559 return -1;
560 }
561 memcpy(&videoCodec, &video_codec_info_, sizeof(VideoCodec));
562 return 0;
563}
564
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000565int32_t VideoFilePlayerImpl::TimeUntilNextVideoFrame()
niklase@google.com470e71d2011-07-07 08:21:25 +0000566{
567 if(_fileFormat != kFileFormatAviFile)
568 {
569 return -1;
570 }
571 if(!_fileModule.IsPlaying())
572 {
573 return -1;
574 }
575 if(_encodedData.payloadSize <= 0)
576 {
577 // Read next frame from file.
578 CriticalSectionScoped lock( _critSec);
579
580 if(_fileFormat == kFileFormatAviFile)
581 {
582 // Get next video frame
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000583 size_t encodedBufferLengthInBytes = _encodedData.bufferSize;
niklase@google.com470e71d2011-07-07 08:21:25 +0000584 if(_fileModule.PlayoutAVIVideoData(
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000585 reinterpret_cast< int8_t*>(_encodedData.payloadData),
niklase@google.com470e71d2011-07-07 08:21:25 +0000586 encodedBufferLengthInBytes) != 0)
587 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000588 LOG(LS_WARNING) << "Error reading video data.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000589 return -1;
590 }
591 _encodedData.payloadSize = encodedBufferLengthInBytes;
592 _encodedData.codec = video_codec_info_.codecType;
593 _numberOfFramesRead++;
594
595 if(_accumulatedRenderTimeMs == 0)
596 {
597 _startTime = TickTime::Now();
598 // This if-statement should only trigger once.
599 _accumulatedRenderTimeMs = 1;
600 } else {
601 // A full seconds worth of frames have been read.
602 if(_numberOfFramesRead % video_codec_info_.maxFramerate == 0)
603 {
604 // Frame rate is in frames per seconds. Frame length is
605 // calculated as an integer division which means it may
606 // be rounded down. Compensate for this every second.
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000607 uint32_t rest = 1000%_frameLengthMS;
niklase@google.com470e71d2011-07-07 08:21:25 +0000608 _accumulatedRenderTimeMs += rest;
609 }
610 _accumulatedRenderTimeMs += _frameLengthMS;
611 }
612 }
613 }
614
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000615 int64_t timeToNextFrame;
niklase@google.com470e71d2011-07-07 08:21:25 +0000616 if(_videoOnly)
617 {
618 timeToNextFrame = _accumulatedRenderTimeMs -
619 (TickTime::Now() - _startTime).Milliseconds();
620
621 } else {
622 // Synchronize with the audio stream instead of system clock.
623 timeToNextFrame = _accumulatedRenderTimeMs - _decodedLengthInMS;
624 }
625 if(timeToNextFrame < 0)
626 {
627 return 0;
628
629 } else if(timeToNextFrame > 0x0fffffff)
630 {
631 // Wraparound or audio stream has gone to far ahead of the video stream.
632 return -1;
633 }
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000634 return static_cast<int32_t>(timeToNextFrame);
niklase@google.com470e71d2011-07-07 08:21:25 +0000635}
636
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000637int32_t VideoFilePlayerImpl::SetUpVideoDecoder()
niklase@google.com470e71d2011-07-07 08:21:25 +0000638{
639 if (_fileModule.VideoCodecInst(video_codec_info_) != 0)
640 {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000641 LOG(LS_WARNING) << "SetVideoDecoder() failed to retrieve codec info of "
642 << "file data.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000643 return -1;
644 }
645
pbos@webrtc.orgc75102e2013-04-09 13:32:55 +0000646 int32_t useNumberOfCores = 1;
andresp@webrtc.org8fa436b2013-09-16 11:26:35 +0000647 if (video_decoder_->SetDecodeCodec(video_codec_info_, useNumberOfCores) !=
648 0) {
asapersson@webrtc.org8b2ec152014-04-11 07:59:43 +0000649 LOG(LS_WARNING) << "SetUpVideoDecoder() codec "
650 << video_codec_info_.plName << " not supported.";
niklase@google.com470e71d2011-07-07 08:21:25 +0000651 return -1;
652 }
653
niklase@google.com470e71d2011-07-07 08:21:25 +0000654 _frameLengthMS = 1000/video_codec_info_.maxFramerate;
655
656 // Size of unencoded data (I420) should be the largest possible frame size
657 // in a file.
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000658 const size_t KReadBufferSize = 3 * video_codec_info_.width *
niklase@google.com470e71d2011-07-07 08:21:25 +0000659 video_codec_info_.height / 2;
660 _encodedData.VerifyAndAllocate(KReadBufferSize);
661 _encodedData.encodedHeight = video_codec_info_.height;
662 _encodedData.encodedWidth = video_codec_info_.width;
663 _encodedData.payloadType = video_codec_info_.plType;
664 _encodedData.timeStamp = 0;
665 return 0;
666}
667#endif // WEBRTC_MODULE_UTILITY_VIDEO
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000668} // namespace webrtc