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
20namespace webrtc {
21FilePlayer* 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
46void FilePlayer::DestroyFilePlayer(FilePlayer* player)
47{
48    delete player;
49}
50
51FilePlayerImpl::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
67FilePlayerImpl::~FilePlayerImpl()
68{
69    MediaFile::DestroyMediaFile(&_fileModule);
70}
71
72int32_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
102int32_t FilePlayerImpl::AudioCodec(CodecInst& audioCodec) const
103{
104    audioCodec = _codec;
105    return 0;
106}
107
108int32_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
201int32_t FilePlayerImpl::RegisterModuleFileCallback(FileCallback* callback)
202{
203    return _fileModule.SetModuleFileCallback(callback);
204}
205
206int32_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
217int32_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
299int32_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
379int32_t FilePlayerImpl::StopPlayingFile()
380{
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
392int32_t FilePlayerImpl::GetPlayoutPosition(uint32_t& durationMs)
393{
394    return _fileModule.PlayoutPositionMs(durationMs);
395}
396
397int32_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
417VideoFilePlayerImpl::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
434VideoFilePlayerImpl::~VideoFilePlayerImpl()
435{
436    delete _critSec;
437    delete &_frameScaler;
438    video_decoder_.reset();
439    delete &_encodedData;
440}
441
442int32_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
479int32_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
489int32_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
508int32_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
555int32_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
566int32_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
638int32_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