LCOV - code coverage report
Current view: top level - dom/media/ogg - OggWriter.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 95 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 9 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             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       4             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : #include "OggWriter.h"
       6             : #include "prtime.h"
       7             : #include "GeckoProfiler.h"
       8             : 
       9             : #undef LOG
      10             : #ifdef MOZ_WIDGET_GONK
      11             : #include <android/log.h>
      12             : #define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "MediaEncoder", ## args);
      13             : #else
      14             : #define LOG(args, ...)
      15             : #endif
      16             : 
      17             : namespace mozilla {
      18             : 
      19           0 : OggWriter::OggWriter() : ContainerWriter()
      20             : {
      21           0 :   if (NS_FAILED(Init())) {
      22             :     LOG("ERROR! Fail to initialize the OggWriter.");
      23             :   }
      24           0 : }
      25             : 
      26           0 : OggWriter::~OggWriter()
      27             : {
      28           0 :   if (mInitialized) {
      29           0 :     ogg_stream_clear(&mOggStreamState);
      30             :   }
      31             :   // mPacket's data was always owned by us, no need to ogg_packet_clear.
      32           0 : }
      33             : 
      34             : nsresult
      35           0 : OggWriter::Init()
      36             : {
      37           0 :   MOZ_ASSERT(!mInitialized);
      38             : 
      39             :   // The serial number (serialno) should be a random number, for the current
      40             :   // implementation where the output file contains only a single stream, this
      41             :   // serialno is used to differentiate between files.
      42           0 :   srand(static_cast<unsigned>(PR_Now()));
      43           0 :   int rc = ogg_stream_init(&mOggStreamState, rand());
      44             : 
      45           0 :   mPacket.b_o_s = 1;
      46           0 :   mPacket.e_o_s = 0;
      47           0 :   mPacket.granulepos = 0;
      48           0 :   mPacket.packet = nullptr;
      49           0 :   mPacket.packetno = 0;
      50           0 :   mPacket.bytes = 0;
      51             : 
      52           0 :   mInitialized = (rc == 0);
      53             : 
      54           0 :   return (rc == 0) ? NS_OK : NS_ERROR_NOT_INITIALIZED;
      55             : }
      56             : 
      57             : nsresult
      58           0 : OggWriter::WriteEncodedTrack(const EncodedFrameContainer& aData,
      59             :                              uint32_t aFlags)
      60             : {
      61           0 :   AUTO_PROFILER_LABEL("OggWriter::WriteEncodedTrack", OTHER);
      62             : 
      63           0 :   uint32_t len = aData.GetEncodedFrames().Length();
      64           0 :   for (uint32_t i = 0; i < len; i++) {
      65           0 :     if (aData.GetEncodedFrames()[i]->GetFrameType() != EncodedFrame::OPUS_AUDIO_FRAME) {
      66             :       LOG("[OggWriter] wrong encoded data type!");
      67           0 :       return NS_ERROR_FAILURE;
      68             :     }
      69             : 
      70             :     // only pass END_OF_STREAM on the last frame!
      71           0 :     nsresult rv = WriteEncodedData(aData.GetEncodedFrames()[i]->GetFrameData(),
      72           0 :                                    aData.GetEncodedFrames()[i]->GetDuration(),
      73           0 :                                    i < len-1 ? (aFlags & ~ContainerWriter::END_OF_STREAM) :
      74           0 :                                    aFlags);
      75           0 :     if (NS_FAILED(rv)) {
      76             :       LOG("%p Failed to WriteEncodedTrack!", this);
      77           0 :       return rv;
      78             :     }
      79             :   }
      80           0 :   return NS_OK;
      81             : }
      82             : 
      83             : nsresult
      84           0 : OggWriter::WriteEncodedData(const nsTArray<uint8_t>& aBuffer, int aDuration,
      85             :                             uint32_t aFlags)
      86             : {
      87           0 :   if (!mInitialized) {
      88             :     LOG("[OggWriter] OggWriter has not initialized!");
      89           0 :     return NS_ERROR_FAILURE;
      90             :   }
      91             : 
      92           0 :   MOZ_ASSERT(!ogg_stream_eos(&mOggStreamState),
      93             :              "No data can be written after eos has marked.");
      94             : 
      95             :   // Set eos flag to true, and once the eos is written to a packet, there must
      96             :   // not be anymore pages after a page has marked as eos.
      97           0 :   if (aFlags & ContainerWriter::END_OF_STREAM) {
      98             :     LOG("[OggWriter] Set e_o_s flag to true.");
      99           0 :     mPacket.e_o_s = 1;
     100             :   }
     101             : 
     102           0 :   mPacket.packet = const_cast<uint8_t*>(aBuffer.Elements());
     103           0 :   mPacket.bytes = aBuffer.Length();
     104           0 :   mPacket.granulepos += aDuration;
     105             : 
     106             :   // 0 returned on success. -1 returned in the event of internal error.
     107             :   // The data in the packet is copied into the internal storage managed by the
     108             :   // mOggStreamState, so we are free to alter the contents of mPacket after
     109             :   // this call has returned.
     110           0 :   int rc = ogg_stream_packetin(&mOggStreamState, &mPacket);
     111           0 :   if (rc < 0) {
     112             :     LOG("[OggWriter] Failed in ogg_stream_packetin! (%d).", rc);
     113           0 :     return NS_ERROR_FAILURE;
     114             :   }
     115             : 
     116           0 :   if (mPacket.b_o_s) {
     117           0 :     mPacket.b_o_s = 0;
     118             :   }
     119           0 :   mPacket.packetno++;
     120           0 :   mPacket.packet = nullptr;
     121             : 
     122           0 :   return NS_OK;
     123             : }
     124             : 
     125             : void
     126           0 : OggWriter::ProduceOggPage(nsTArray<nsTArray<uint8_t> >* aOutputBufs)
     127             : {
     128           0 :   aOutputBufs->AppendElement();
     129           0 :   aOutputBufs->LastElement().SetLength(mOggPage.header_len +
     130           0 :                                        mOggPage.body_len);
     131           0 :   memcpy(aOutputBufs->LastElement().Elements(), mOggPage.header,
     132           0 :          mOggPage.header_len);
     133           0 :   memcpy(aOutputBufs->LastElement().Elements() + mOggPage.header_len,
     134           0 :          mOggPage.body, mOggPage.body_len);
     135           0 : }
     136             : 
     137             : nsresult
     138           0 : OggWriter::GetContainerData(nsTArray<nsTArray<uint8_t> >* aOutputBufs,
     139             :                             uint32_t aFlags)
     140             : {
     141           0 :   int rc = -1;
     142           0 :   AUTO_PROFILER_LABEL("OggWriter::GetContainerData", OTHER);
     143             :   // Generate the oggOpus Header
     144           0 :   if (aFlags & ContainerWriter::GET_HEADER) {
     145           0 :     OpusMetadata* meta = static_cast<OpusMetadata*>(mMetadata.get());
     146           0 :     NS_ASSERTION(meta, "should have meta data");
     147           0 :     NS_ASSERTION(meta->GetKind() == TrackMetadataBase::METADATA_OPUS,
     148             :                  "should have Opus meta data");
     149             : 
     150           0 :     nsresult rv = WriteEncodedData(meta->mIdHeader, 0);
     151           0 :     NS_ENSURE_SUCCESS(rv, rv);
     152             : 
     153           0 :     rc = ogg_stream_flush(&mOggStreamState, &mOggPage);
     154           0 :     NS_ENSURE_TRUE(rc > 0, NS_ERROR_FAILURE);
     155           0 :     ProduceOggPage(aOutputBufs);
     156             : 
     157           0 :     rv = WriteEncodedData(meta->mCommentHeader, 0);
     158           0 :     NS_ENSURE_SUCCESS(rv, rv);
     159             : 
     160           0 :     rc = ogg_stream_flush(&mOggStreamState, &mOggPage);
     161           0 :     NS_ENSURE_TRUE(rc > 0, NS_ERROR_FAILURE);
     162             : 
     163           0 :     ProduceOggPage(aOutputBufs);
     164           0 :     return NS_OK;
     165             : 
     166             :   // Force generate a page even if the amount of packet data is not enough.
     167             :   // Usually do so after a header packet.
     168           0 :   } else if (aFlags & ContainerWriter::FLUSH_NEEDED) {
     169             :     // rc = 0 means no packet to put into a page, or an internal error.
     170           0 :     rc = ogg_stream_flush(&mOggStreamState, &mOggPage);
     171             :   } else {
     172             :     // rc = 0 means insufficient data has accumulated to fill a page, or an
     173             :     // internal error has occurred.
     174           0 :     rc = ogg_stream_pageout(&mOggStreamState, &mOggPage);
     175             :   }
     176             : 
     177           0 :   if (rc) {
     178           0 :     ProduceOggPage(aOutputBufs);
     179             :   }
     180           0 :   if (aFlags & ContainerWriter::FLUSH_NEEDED) {
     181           0 :     mIsWritingComplete = true;
     182             :   }
     183           0 :   return (rc > 0) ? NS_OK : NS_ERROR_FAILURE;
     184             : }
     185             : 
     186             : nsresult
     187           0 : OggWriter::SetMetadata(TrackMetadataBase* aMetadata)
     188             : {
     189           0 :   MOZ_ASSERT(aMetadata);
     190             : 
     191           0 :   AUTO_PROFILER_LABEL("OggWriter::SetMetadata", OTHER);
     192             : 
     193           0 :   if (aMetadata->GetKind() != TrackMetadataBase::METADATA_OPUS) {
     194             :     LOG("wrong meta data type!");
     195           0 :     return NS_ERROR_FAILURE;
     196             :   }
     197             :   // Validate each field of METADATA
     198           0 :   mMetadata = static_cast<OpusMetadata*>(aMetadata);
     199           0 :   if (mMetadata->mIdHeader.Length() == 0) {
     200             :     LOG("miss mIdHeader!");
     201           0 :     return NS_ERROR_FAILURE;
     202             :   }
     203           0 :   if (mMetadata->mCommentHeader.Length() == 0) {
     204             :     LOG("miss mCommentHeader!");
     205           0 :     return NS_ERROR_FAILURE;
     206             :   }
     207             : 
     208           0 :   return NS_OK;
     209             : }
     210             : 
     211             : } // namespace mozilla

Generated by: LCOV version 1.13