LCOV - code coverage report
Current view: top level - dom/media/platforms/ffmpeg - FFmpegAudioDecoder.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 125 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 41 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/TaskQueue.h"
       8             : 
       9             : #include "FFmpegAudioDecoder.h"
      10             : #include "TimeUnits.h"
      11             : 
      12             : #define MAX_CHANNELS 16
      13             : 
      14             : namespace mozilla {
      15             : 
      16           0 : FFmpegAudioDecoder<LIBAV_VER>::FFmpegAudioDecoder(FFmpegLibWrapper* aLib,
      17           0 :   TaskQueue* aTaskQueue, const AudioInfo& aConfig)
      18           0 :   : FFmpegDataDecoder(aLib, aTaskQueue, GetCodecId(aConfig.mMimeType))
      19             : {
      20           0 :   MOZ_COUNT_CTOR(FFmpegAudioDecoder);
      21             :   // Use a new MediaByteBuffer as the object will be modified during
      22             :   // initialization.
      23           0 :   if (aConfig.mCodecSpecificConfig && aConfig.mCodecSpecificConfig->Length()) {
      24           0 :     mExtraData = new MediaByteBuffer;
      25           0 :     mExtraData->AppendElements(*aConfig.mCodecSpecificConfig);
      26             :   }
      27           0 : }
      28             : 
      29             : RefPtr<MediaDataDecoder::InitPromise>
      30           0 : FFmpegAudioDecoder<LIBAV_VER>::Init()
      31             : {
      32           0 :   nsresult rv = InitDecoder();
      33             : 
      34             :   return rv == NS_OK
      35             :          ? InitPromise::CreateAndResolve(TrackInfo::kAudioTrack, __func__)
      36             :          : InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
      37           0 :                                         __func__);
      38             : }
      39             : 
      40             : void
      41           0 : FFmpegAudioDecoder<LIBAV_VER>::InitCodecContext()
      42             : {
      43           0 :   MOZ_ASSERT(mCodecContext);
      44             :   // We do not want to set this value to 0 as FFmpeg by default will
      45             :   // use the number of cores, which with our mozlibavutil get_cpu_count
      46             :   // isn't implemented.
      47           0 :   mCodecContext->thread_count = 1;
      48             :   // FFmpeg takes this as a suggestion for what format to use for audio samples.
      49             :   // LibAV 0.8 produces rubbish float interleaved samples, request 16 bits
      50             :   // audio.
      51           0 :   mCodecContext->request_sample_fmt =
      52           0 :     (mLib->mVersion == 53) ? AV_SAMPLE_FMT_S16 : AV_SAMPLE_FMT_FLT;
      53           0 : }
      54             : 
      55             : static AlignedAudioBuffer
      56           0 : CopyAndPackAudio(AVFrame* aFrame, uint32_t aNumChannels, uint32_t aNumAFrames)
      57             : {
      58           0 :   MOZ_ASSERT(aNumChannels <= MAX_CHANNELS);
      59             : 
      60           0 :   AlignedAudioBuffer audio(aNumChannels * aNumAFrames);
      61           0 :   if (!audio) {
      62           0 :     return audio;
      63             :   }
      64             : 
      65           0 :   if (aFrame->format == AV_SAMPLE_FMT_FLT) {
      66             :     // Audio data already packed. No need to do anything other than copy it
      67             :     // into a buffer we own.
      68           0 :     memcpy(audio.get(), aFrame->data[0],
      69           0 :            aNumChannels * aNumAFrames * sizeof(AudioDataValue));
      70           0 :   } else if (aFrame->format == AV_SAMPLE_FMT_FLTP) {
      71             :     // Planar audio data. Pack it into something we can understand.
      72           0 :     AudioDataValue* tmp = audio.get();
      73           0 :     AudioDataValue** data = reinterpret_cast<AudioDataValue**>(aFrame->data);
      74           0 :     for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
      75           0 :       for (uint32_t channel = 0; channel < aNumChannels; channel++) {
      76           0 :         *tmp++ = data[channel][frame];
      77             :       }
      78             :     }
      79           0 :   } else if (aFrame->format == AV_SAMPLE_FMT_S16) {
      80             :     // Audio data already packed. Need to convert from S16 to 32 bits Float
      81           0 :     AudioDataValue* tmp = audio.get();
      82           0 :     int16_t* data = reinterpret_cast<int16_t**>(aFrame->data)[0];
      83           0 :     for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
      84           0 :       for (uint32_t channel = 0; channel < aNumChannels; channel++) {
      85           0 :         *tmp++ = AudioSampleToFloat(*data++);
      86             :       }
      87             :     }
      88           0 :   } else if (aFrame->format == AV_SAMPLE_FMT_S16P) {
      89             :     // Planar audio data. Convert it from S16 to 32 bits float
      90             :     // and pack it into something we can understand.
      91           0 :     AudioDataValue* tmp = audio.get();
      92           0 :     int16_t** data = reinterpret_cast<int16_t**>(aFrame->data);
      93           0 :     for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
      94           0 :       for (uint32_t channel = 0; channel < aNumChannels; channel++) {
      95           0 :         *tmp++ = AudioSampleToFloat(data[channel][frame]);
      96             :       }
      97             :     }
      98           0 :   } else if (aFrame->format == AV_SAMPLE_FMT_S32) {
      99             :     // Audio data already packed. Need to convert from S16 to 32 bits Float
     100           0 :     AudioDataValue* tmp = audio.get();
     101           0 :     int32_t* data = reinterpret_cast<int32_t**>(aFrame->data)[0];
     102           0 :     for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
     103           0 :       for (uint32_t channel = 0; channel < aNumChannels; channel++) {
     104           0 :         *tmp++ = AudioSampleToFloat(*data++);
     105             :       }
     106             :     }
     107           0 :   } else if (aFrame->format == AV_SAMPLE_FMT_S32P) {
     108             :     // Planar audio data. Convert it from S32 to 32 bits float
     109             :     // and pack it into something we can understand.
     110           0 :     AudioDataValue* tmp = audio.get();
     111           0 :     int32_t** data = reinterpret_cast<int32_t**>(aFrame->data);
     112           0 :     for (uint32_t frame = 0; frame < aNumAFrames; frame++) {
     113           0 :       for (uint32_t channel = 0; channel < aNumChannels; channel++) {
     114           0 :         *tmp++ = AudioSampleToFloat(data[channel][frame]);
     115             :       }
     116             :     }
     117             :   }
     118             : 
     119           0 :   return audio;
     120             : }
     121             : 
     122             : RefPtr<MediaDataDecoder::DecodePromise>
     123           0 : FFmpegAudioDecoder<LIBAV_VER>::ProcessDecode(MediaRawData* aSample)
     124             : {
     125             :   AVPacket packet;
     126           0 :   mLib->av_init_packet(&packet);
     127             : 
     128           0 :   packet.data = const_cast<uint8_t*>(aSample->Data());
     129           0 :   packet.size = aSample->Size();
     130             : 
     131           0 :   if (!PrepareFrame()) {
     132             :     return DecodePromise::CreateAndReject(
     133           0 :       MediaResult(
     134             :         NS_ERROR_OUT_OF_MEMORY,
     135           0 :         RESULT_DETAIL("FFmpeg audio decoder failed to allocate frame")),
     136           0 :       __func__);
     137             :   }
     138             : 
     139           0 :   int64_t samplePosition = aSample->mOffset;
     140           0 :   media::TimeUnit pts = aSample->mTime;
     141             : 
     142           0 :   DecodedData results;
     143           0 :   while (packet.size > 0) {
     144             :     int decoded;
     145             :     int bytesConsumed =
     146           0 :       mLib->avcodec_decode_audio4(mCodecContext, mFrame, &decoded, &packet);
     147             : 
     148           0 :     if (bytesConsumed < 0) {
     149           0 :       NS_WARNING("FFmpeg audio decoder error.");
     150             :       return DecodePromise::CreateAndReject(
     151           0 :         MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
     152           0 :                     RESULT_DETAIL("FFmpeg audio error:%d", bytesConsumed)),
     153           0 :         __func__);
     154             :     }
     155             : 
     156           0 :     if (decoded) {
     157           0 :       if (mFrame->format != AV_SAMPLE_FMT_FLT &&
     158           0 :           mFrame->format != AV_SAMPLE_FMT_FLTP &&
     159           0 :           mFrame->format != AV_SAMPLE_FMT_S16 &&
     160           0 :           mFrame->format != AV_SAMPLE_FMT_S16P &&
     161           0 :           mFrame->format != AV_SAMPLE_FMT_S32 &&
     162           0 :           mFrame->format != AV_SAMPLE_FMT_S32P) {
     163             :         return DecodePromise::CreateAndReject(
     164           0 :           MediaResult(
     165             :             NS_ERROR_DOM_MEDIA_DECODE_ERR,
     166           0 :             RESULT_DETAIL(
     167             :               "FFmpeg audio decoder outputs unsupported audio format")),
     168           0 :           __func__);
     169             :       }
     170           0 :       uint32_t numChannels = mCodecContext->channels;
     171           0 :       AudioConfig::ChannelLayout layout(numChannels);
     172           0 :       if (!layout.IsValid()) {
     173             :         return DecodePromise::CreateAndReject(
     174           0 :           MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
     175           0 :                       RESULT_DETAIL("Unsupported channel layout:%u", numChannels)),
     176           0 :           __func__);
     177             :       }
     178             : 
     179           0 :       uint32_t samplingRate = mCodecContext->sample_rate;
     180             : 
     181             :       AlignedAudioBuffer audio =
     182           0 :         CopyAndPackAudio(mFrame, numChannels, mFrame->nb_samples);
     183           0 :       if (!audio) {
     184             :         return DecodePromise::CreateAndReject(
     185           0 :           MediaResult(NS_ERROR_OUT_OF_MEMORY, __func__), __func__);
     186             :       }
     187             : 
     188             :       media::TimeUnit duration =
     189           0 :         FramesToTimeUnit(mFrame->nb_samples, samplingRate);
     190           0 :       if (!duration.IsValid()) {
     191             :         return DecodePromise::CreateAndReject(
     192           0 :           MediaResult(NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
     193           0 :                       RESULT_DETAIL("Invalid sample duration")),
     194           0 :           __func__);
     195             :       }
     196             : 
     197           0 :       media::TimeUnit newpts = pts + duration;
     198           0 :       if (!newpts.IsValid()) {
     199             :         return DecodePromise::CreateAndReject(
     200           0 :           MediaResult(
     201             :             NS_ERROR_DOM_MEDIA_OVERFLOW_ERR,
     202           0 :             RESULT_DETAIL("Invalid count of accumulated audio samples")),
     203           0 :           __func__);
     204             :       }
     205             : 
     206           0 :       results.AppendElement(new AudioData(
     207             :         samplePosition, pts, duration,
     208           0 :         mFrame->nb_samples, Move(audio), numChannels, samplingRate));
     209             : 
     210           0 :       pts = newpts;
     211             :     }
     212           0 :     packet.data += bytesConsumed;
     213           0 :     packet.size -= bytesConsumed;
     214           0 :     samplePosition += bytesConsumed;
     215             :   }
     216           0 :   return DecodePromise::CreateAndResolve(Move(results), __func__);
     217             : }
     218             : 
     219             : RefPtr<MediaDataDecoder::DecodePromise>
     220           0 : FFmpegAudioDecoder<LIBAV_VER>::ProcessDrain()
     221             : {
     222           0 :   ProcessFlush();
     223           0 :   return DecodePromise::CreateAndResolve(DecodedData(), __func__);
     224             : }
     225             : 
     226             : AVCodecID
     227           0 : FFmpegAudioDecoder<LIBAV_VER>::GetCodecId(const nsACString& aMimeType)
     228             : {
     229           0 :   if (aMimeType.EqualsLiteral("audio/mpeg")) {
     230           0 :     return AV_CODEC_ID_MP3;
     231           0 :   } else if (aMimeType.EqualsLiteral("audio/flac")) {
     232           0 :     return AV_CODEC_ID_FLAC;
     233           0 :   } else if (aMimeType.EqualsLiteral("audio/mp4a-latm")) {
     234           0 :     return AV_CODEC_ID_AAC;
     235             :   }
     236             : 
     237           0 :   return AV_CODEC_ID_NONE;
     238             : }
     239             : 
     240           0 : FFmpegAudioDecoder<LIBAV_VER>::~FFmpegAudioDecoder()
     241             : {
     242           0 :   MOZ_COUNT_DTOR(FFmpegAudioDecoder);
     243           0 : }
     244             : 
     245             : } // namespace mozilla

Generated by: LCOV version 1.13