1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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 "webrtc/modules/utility/source/file_player_impl.h"
12 #include "webrtc/system_wrappers/interface/logging.h"
13
14 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
15 #include "frame_scaler.h"
16 #include "tick_util.h"
17 #include "video_coder.h"
18 #endif
19
20 namespace webrtc {
CreateFilePlayer(uint32_t instanceID,FileFormats fileFormat)21 FilePlayer* FilePlayer::CreateFilePlayer(uint32_t instanceID,
22 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);
34 case kFileFormatAviFile:
35 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
36 return new VideoFilePlayerImpl(instanceID, fileFormat);
37 #else
38 assert(false);
39 return NULL;
40 #endif
41 }
42 assert(false);
43 return NULL;
44 }
45
DestroyFilePlayer(FilePlayer * player)46 void FilePlayer::DestroyFilePlayer(FilePlayer* player)
47 {
48 delete player;
49 }
50
FilePlayerImpl(const uint32_t instanceID,const FileFormats fileFormat)51 FilePlayerImpl::FilePlayerImpl(const uint32_t instanceID,
52 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),
61 _resampler(),
62 _scaling(1.0)
63 {
64 _codec.plfreq = 0;
65 }
66
~FilePlayerImpl()67 FilePlayerImpl::~FilePlayerImpl()
68 {
69 MediaFile::DestroyMediaFile(&_fileModule);
70 }
71
Frequency() const72 int32_t FilePlayerImpl::Frequency() const
73 {
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
AudioCodec(CodecInst & audioCodec) const102 int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const
103 {
104 audioCodec = _codec;
105 return 0;
106 }
107
Get10msAudioFromFile(int16_t * outBuffer,int & lengthInSamples,int frequencyInHz)108 int32_t FilePlayerImpl::Get10msAudioFromFile(
109 int16_t* outBuffer,
110 int& lengthInSamples,
111 int frequencyInHz)
112 {
113 if(_codec.plfreq == 0)
114 {
115 LOG(LS_WARNING) << "Get10msAudioFromFile() playing not started!"
116 << " codec freq = " << _codec.plfreq
117 << ", wanted freq = " << frequencyInHz;
118 return -1;
119 }
120
121 AudioFrame unresampledAudioFrame;
122 if(STR_CASE_CMP(_codec.plname, "L16") == 0)
123 {
124 unresampledAudioFrame.sample_rate_hz_ = _codec.plfreq;
125
126 // L16 is un-encoded data. Just pull 10 ms.
127 uint32_t lengthInBytes =
128 sizeof(unresampledAudioFrame.data_);
129 if (_fileModule.PlayoutAudioData(
130 (int8_t*)unresampledAudioFrame.data_,
131 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.
142 unresampledAudioFrame.samples_per_channel_ =
143 (uint16_t)lengthInBytes >> 1;
144
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.
149 int16_t encodedBuffer[MAX_AUDIO_BUFFER_IN_SAMPLES];
150 uint32_t encodedLengthInBytes = 0;
151 if(++_numberOf10MsInDecoder >= _numberOf10MsPerFrame)
152 {
153 _numberOf10MsInDecoder = 0;
154 uint32_t bytesFromFile = sizeof(encodedBuffer);
155 if (_fileModule.PlayoutAudioData((int8_t*)encodedBuffer,
156 bytesFromFile) == -1)
157 {
158 // End of file reached.
159 return -1;
160 }
161 encodedLengthInBytes = bytesFromFile;
162 }
163 if(_audioDecoder.Decode(unresampledAudioFrame,frequencyInHz,
164 (int8_t*)encodedBuffer,
165 encodedLengthInBytes) == -1)
166 {
167 return -1;
168 }
169 }
170
171 int outLen = 0;
172 if(_resampler.ResetIfNeeded(unresampledAudioFrame.sample_rate_hz_,
173 frequencyInHz, kResamplerSynchronous))
174 {
175 LOG(LS_WARNING) << "Get10msAudioFromFile() unexpected codec.";
176
177 // New sampling frequency. Update state.
178 outLen = frequencyInHz / 100;
179 memset(outBuffer, 0, outLen * sizeof(int16_t));
180 return 0;
181 }
182 _resampler.Push(unresampledAudioFrame.data_,
183 unresampledAudioFrame.samples_per_channel_,
184 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 {
194 outBuffer[i] = (int16_t)(outBuffer[i] * _scaling);
195 }
196 }
197 _decodedLengthInMS += 10;
198 return 0;
199 }
200
RegisterModuleFileCallback(FileCallback * callback)201 int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback)
202 {
203 return _fileModule.SetModuleFileCallback(callback);
204 }
205
SetAudioScaling(float scaleFactor)206 int32_t FilePlayerImpl::SetAudioScaling(float scaleFactor)
207 {
208 if((scaleFactor >= 0)&&(scaleFactor <= 2.0))
209 {
210 _scaling = scaleFactor;
211 return 0;
212 }
213 LOG(LS_WARNING) << "SetAudioScaling() non-allowed scale factor.";
214 return -1;
215 }
216
StartPlayingFile(const char * fileName,bool loop,uint32_t startPosition,float volumeScaling,uint32_t notification,uint32_t stopPosition,const CodecInst * codecInst)217 int32_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)
224 {
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 {
253 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
254 << "supported for PCM format.";
255 return -1;
256 }
257
258 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
259 _fileFormat, &codecInstL16,
260 startPosition,
261 stopPosition) == -1)
262 {
263 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
264 << "pcm file " << fileName;
265 return -1;
266 }
267 SetAudioScaling(volumeScaling);
268 }else if(_fileFormat == kFileFormatPreencodedFile)
269 {
270 if (_fileModule.StartPlayingAudioFile(fileName, notification, loop,
271 _fileFormat, codecInst) == -1)
272 {
273 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize "
274 << "pre-encoded file " << fileName;
275 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 {
285 LOG(LS_WARNING) << "StartPlayingFile() failed to initialize file "
286 << fileName;
287 return -1;
288 }
289 SetAudioScaling(volumeScaling);
290 }
291 if (SetUpAudioDecoder() == -1)
292 {
293 StopPlayingFile();
294 return -1;
295 }
296 return 0;
297 }
298
StartPlayingFile(InStream & sourceStream,uint32_t startPosition,float volumeScaling,uint32_t notification,uint32_t stopPosition,const CodecInst * codecInst)299 int32_t FilePlayerImpl::StartPlayingFile(InStream& sourceStream,
300 uint32_t startPosition,
301 float volumeScaling,
302 uint32_t notification,
303 uint32_t stopPosition,
304 const CodecInst* codecInst)
305 {
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 {
334 LOG(LS_ERROR) << "StartPlayingFile() sample frequency not "
335 << "supported for PCM format.";
336 return -1;
337 }
338 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
339 _fileFormat, &codecInstL16,
340 startPosition,
341 stopPosition) == -1)
342 {
343 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
344 << "playout.";
345 return -1;
346 }
347
348 }else if(_fileFormat == kFileFormatPreencodedFile)
349 {
350 if (_fileModule.StartPlayingAudioStream(sourceStream, notification,
351 _fileFormat, codecInst) == -1)
352 {
353 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
354 << "playout.";
355 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 {
364 LOG(LS_ERROR) << "StartPlayingFile() failed to initialize stream "
365 << "playout.";
366 return -1;
367 }
368 }
369 SetAudioScaling(volumeScaling);
370
371 if (SetUpAudioDecoder() == -1)
372 {
373 StopPlayingFile();
374 return -1;
375 }
376 return 0;
377 }
378
StopPlayingFile()379 int32_t FilePlayerImpl::StopPlayingFile()
380 {
381 memset(&_codec, 0, sizeof(CodecInst));
382 _numberOf10MsPerFrame = 0;
383 _numberOf10MsInDecoder = 0;
384 return _fileModule.StopPlaying();
385 }
386
IsPlayingFile() const387 bool FilePlayerImpl::IsPlayingFile() const
388 {
389 return _fileModule.IsPlaying();
390 }
391
GetPlayoutPosition(uint32_t & durationMs)392 int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs)
393 {
394 return _fileModule.PlayoutPositionMs(durationMs);
395 }
396
SetUpAudioDecoder()397 int32_t FilePlayerImpl::SetUpAudioDecoder()
398 {
399 if ((_fileModule.codec_info(_codec) == -1))
400 {
401 LOG(LS_WARNING) << "Failed to retrieve codec info of file data.";
402 return -1;
403 }
404 if( STR_CASE_CMP(_codec.plname, "L16") != 0 &&
405 _audioDecoder.SetDecodeCodec(_codec,AMRFileStorage) == -1)
406 {
407 LOG(LS_WARNING) << "SetUpAudioDecoder() codec " << _codec.plname
408 << " not supported.";
409 return -1;
410 }
411 _numberOf10MsPerFrame = _codec.pacsize / (_codec.plfreq / 100);
412 _numberOf10MsInDecoder = 0;
413 return 0;
414 }
415
416 #ifdef WEBRTC_MODULE_UTILITY_VIDEO
VideoFilePlayerImpl(uint32_t instanceID,FileFormats fileFormat)417 VideoFilePlayerImpl::VideoFilePlayerImpl(uint32_t instanceID,
418 FileFormats fileFormat)
419 : FilePlayerImpl(instanceID, fileFormat),
420 video_decoder_(new VideoCoder()),
421 video_codec_info_(),
422 _decodedVideoFrames(0),
423 _encodedData(*new EncodedVideoData()),
424 _frameScaler(*new FrameScaler()),
425 _critSec(CriticalSectionWrapper::CreateCriticalSection()),
426 _startTime(),
427 _accumulatedRenderTimeMs(0),
428 _frameLengthMS(0),
429 _numberOfFramesRead(0),
430 _videoOnly(false) {
431 memset(&video_codec_info_, 0, sizeof(video_codec_info_));
432 }
433
~VideoFilePlayerImpl()434 VideoFilePlayerImpl::~VideoFilePlayerImpl()
435 {
436 delete _critSec;
437 delete &_frameScaler;
438 video_decoder_.reset();
439 delete &_encodedData;
440 }
441
StartPlayingVideoFile(const char * fileName,bool loop,bool videoOnly)442 int32_t VideoFilePlayerImpl::StartPlayingVideoFile(
443 const char* fileName,
444 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
StopPlayingFile()479 int32_t VideoFilePlayerImpl::StopPlayingFile()
480 {
481 CriticalSectionScoped lock( _critSec);
482
483 _decodedVideoFrames = 0;
484 video_decoder_.reset(new VideoCoder());
485
486 return FilePlayerImpl::StopPlayingFile();
487 }
488
GetVideoFromFile(I420VideoFrame & videoFrame,uint32_t outWidth,uint32_t outHeight)489 int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame,
490 uint32_t outWidth,
491 uint32_t outHeight)
492 {
493 CriticalSectionScoped lock( _critSec);
494
495 int32_t retVal = GetVideoFromFile(videoFrame);
496 if(retVal != 0)
497 {
498 return retVal;
499 }
500 if (!videoFrame.IsZeroSize())
501 {
502 retVal = _frameScaler.ResizeFrameIfNeeded(&videoFrame, outWidth,
503 outHeight);
504 }
505 return retVal;
506 }
507
GetVideoFromFile(I420VideoFrame & videoFrame)508 int32_t VideoFilePlayerImpl::GetVideoFromFile(I420VideoFrame& videoFrame)
509 {
510 CriticalSectionScoped lock( _critSec);
511 // No new video data read from file.
512 if(_encodedData.payloadSize == 0)
513 {
514 videoFrame.ResetSize();
515 return -1;
516 }
517 int32_t retVal = 0;
518 if(strncmp(video_codec_info_.plName, "I420", 5) == 0)
519 {
520 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);
534 }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);
539 retVal = video_decoder_->Decode(videoFrame, _encodedData);
540 }
541
542 int64_t renderTimeMs = TickTime::MillisecondTimestamp();
543 videoFrame.set_render_time_ms(renderTimeMs);
544
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
video_codec_info(VideoCodec & videoCodec) const555 int32_t VideoFilePlayerImpl::video_codec_info(
556 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
TimeUntilNextVideoFrame()566 int32_t VideoFilePlayerImpl::TimeUntilNextVideoFrame()
567 {
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
584 uint32_t encodedBufferLengthInBytes = _encodedData.bufferSize;
585 if(_fileModule.PlayoutAVIVideoData(
586 reinterpret_cast< int8_t*>(_encodedData.payloadData),
587 encodedBufferLengthInBytes) != 0)
588 {
589 LOG(LS_WARNING) << "Error reading video data.";
590 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.
608 uint32_t rest = 1000%_frameLengthMS;
609 _accumulatedRenderTimeMs += rest;
610 }
611 _accumulatedRenderTimeMs += _frameLengthMS;
612 }
613 }
614 }
615
616 int64_t timeToNextFrame;
617 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 }
635 return static_cast<int32_t>(timeToNextFrame);
636 }
637
SetUpVideoDecoder()638 int32_t VideoFilePlayerImpl::SetUpVideoDecoder()
639 {
640 if (_fileModule.VideoCodecInst(video_codec_info_) != 0)
641 {
642 LOG(LS_WARNING) << "SetVideoDecoder() failed to retrieve codec info of "
643 << "file data.";
644 return -1;
645 }
646
647 int32_t useNumberOfCores = 1;
648 if (video_decoder_->SetDecodeCodec(video_codec_info_, useNumberOfCores) !=
649 0) {
650 LOG(LS_WARNING) << "SetUpVideoDecoder() codec "
651 << video_codec_info_.plName << " not supported.";
652 return -1;
653 }
654
655 _frameLengthMS = 1000/video_codec_info_.maxFramerate;
656
657 // Size of unencoded data (I420) should be the largest possible frame size
658 // in a file.
659 const uint32_t KReadBufferSize = 3 * video_codec_info_.width *
660 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
669 } // namespace webrtc
670