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 
6 #include "WebMWriter.h"
7 #include "EbmlComposer.h"
8 #include "GeckoProfiler.h"
9 #include "OpusTrackEncoder.h"
10 
11 namespace mozilla {
12 
WebMWriter()13 WebMWriter::WebMWriter()
14     : ContainerWriter(), mEbmlComposer(new EbmlComposer()) {}
15 
~WebMWriter()16 WebMWriter::~WebMWriter() {
17   // Out-of-line dtor so mEbmlComposer UniquePtr can delete a complete type.
18 }
19 
WriteEncodedTrack(const nsTArray<RefPtr<EncodedFrame>> & aData,uint32_t aFlags)20 nsresult WebMWriter::WriteEncodedTrack(
21     const nsTArray<RefPtr<EncodedFrame>>& aData, uint32_t aFlags) {
22   AUTO_PROFILER_LABEL("WebMWriter::WriteEncodedTrack", OTHER);
23   for (uint32_t i = 0; i < aData.Length(); i++) {
24     mEbmlComposer->WriteSimpleBlock(aData.ElementAt(i).get());
25   }
26   return NS_OK;
27 }
28 
GetContainerData(nsTArray<nsTArray<uint8_t>> * aOutputBufs,uint32_t aFlags)29 nsresult WebMWriter::GetContainerData(nsTArray<nsTArray<uint8_t>>* aOutputBufs,
30                                       uint32_t aFlags) {
31   AUTO_PROFILER_LABEL("WebMWriter::GetContainerData", OTHER);
32   mEbmlComposer->ExtractBuffer(aOutputBufs, aFlags);
33   if (aFlags & ContainerWriter::FLUSH_NEEDED) {
34     mIsWritingComplete = true;
35   }
36   return NS_OK;
37 }
38 
SetMetadata(const nsTArray<RefPtr<TrackMetadataBase>> & aMetadata)39 nsresult WebMWriter::SetMetadata(
40     const nsTArray<RefPtr<TrackMetadataBase>>& aMetadata) {
41   AUTO_PROFILER_LABEL("WebMWriter::SetMetadata", OTHER);
42   MOZ_DIAGNOSTIC_ASSERT(!aMetadata.IsEmpty());
43 
44   // Integrity checks
45   bool bad = false;
46   for (const RefPtr<TrackMetadataBase>& metadata : aMetadata) {
47     MOZ_ASSERT(metadata);
48 
49     if (metadata->GetKind() == TrackMetadataBase::METADATA_VP8) {
50       VP8Metadata* meta = static_cast<VP8Metadata*>(metadata.get());
51       if (meta->mWidth == 0 || meta->mHeight == 0 || meta->mDisplayWidth == 0 ||
52           meta->mDisplayHeight == 0) {
53         bad = true;
54       }
55     }
56 
57     if (metadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
58       VorbisMetadata* meta = static_cast<VorbisMetadata*>(metadata.get());
59       if (meta->mSamplingFrequency == 0 || meta->mChannels == 0 ||
60           meta->mData.IsEmpty()) {
61         bad = true;
62       }
63     }
64 
65     if (metadata->GetKind() == TrackMetadataBase::METADATA_OPUS) {
66       OpusMetadata* meta = static_cast<OpusMetadata*>(metadata.get());
67       if (meta->mSamplingFrequency == 0 || meta->mChannels == 0 ||
68           meta->mIdHeader.IsEmpty()) {
69         bad = true;
70       }
71     }
72   }
73   if (bad) {
74     return NS_ERROR_FAILURE;
75   }
76 
77   // Storing
78   DebugOnly<bool> hasAudio = false;
79   DebugOnly<bool> hasVideo = false;
80   for (const RefPtr<TrackMetadataBase>& metadata : aMetadata) {
81     MOZ_ASSERT(metadata);
82 
83     if (metadata->GetKind() == TrackMetadataBase::METADATA_VP8) {
84       MOZ_ASSERT(!hasVideo);
85       VP8Metadata* meta = static_cast<VP8Metadata*>(metadata.get());
86       mEbmlComposer->SetVideoConfig(meta->mWidth, meta->mHeight,
87                                     meta->mDisplayWidth, meta->mDisplayHeight);
88       hasVideo = true;
89     }
90 
91     if (metadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
92       MOZ_ASSERT(!hasAudio);
93       VorbisMetadata* meta = static_cast<VorbisMetadata*>(metadata.get());
94       mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels);
95       mEbmlComposer->SetAudioCodecPrivateData(meta->mData);
96       hasAudio = true;
97     }
98 
99     if (metadata->GetKind() == TrackMetadataBase::METADATA_OPUS) {
100       MOZ_ASSERT(!hasAudio);
101       OpusMetadata* meta = static_cast<OpusMetadata*>(metadata.get());
102       mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels);
103       mEbmlComposer->SetAudioCodecPrivateData(meta->mIdHeader);
104       hasAudio = true;
105     }
106   }
107   mEbmlComposer->GenerateHeader();
108   return NS_OK;
109 }
110 
111 }  // namespace mozilla
112