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 "mozilla/ProfilerLabels.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     nsresult rv = mEbmlComposer->WriteSimpleBlock(aData.ElementAt(i).get());
25     NS_ENSURE_SUCCESS(rv, rv);
26   }
27   return NS_OK;
28 }
29 
GetContainerData(nsTArray<nsTArray<uint8_t>> * aOutputBufs,uint32_t aFlags)30 nsresult WebMWriter::GetContainerData(nsTArray<nsTArray<uint8_t>>* aOutputBufs,
31                                       uint32_t aFlags) {
32   AUTO_PROFILER_LABEL("WebMWriter::GetContainerData", OTHER);
33   mEbmlComposer->ExtractBuffer(aOutputBufs, aFlags);
34   if (aFlags & ContainerWriter::FLUSH_NEEDED) {
35     mIsWritingComplete = true;
36   }
37   return NS_OK;
38 }
39 
SetMetadata(const nsTArray<RefPtr<TrackMetadataBase>> & aMetadata)40 nsresult WebMWriter::SetMetadata(
41     const nsTArray<RefPtr<TrackMetadataBase>>& aMetadata) {
42   AUTO_PROFILER_LABEL("WebMWriter::SetMetadata", OTHER);
43   MOZ_DIAGNOSTIC_ASSERT(!aMetadata.IsEmpty());
44 
45   // Integrity checks
46   bool bad = false;
47   for (const RefPtr<TrackMetadataBase>& metadata : aMetadata) {
48     MOZ_ASSERT(metadata);
49 
50     if (metadata->GetKind() == TrackMetadataBase::METADATA_VP8) {
51       VP8Metadata* meta = static_cast<VP8Metadata*>(metadata.get());
52       if (meta->mWidth == 0 || meta->mHeight == 0 || meta->mDisplayWidth == 0 ||
53           meta->mDisplayHeight == 0) {
54         bad = true;
55       }
56     }
57 
58     if (metadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
59       VorbisMetadata* meta = static_cast<VorbisMetadata*>(metadata.get());
60       if (meta->mSamplingFrequency == 0 || meta->mChannels == 0 ||
61           meta->mData.IsEmpty()) {
62         bad = true;
63       }
64     }
65 
66     if (metadata->GetKind() == TrackMetadataBase::METADATA_OPUS) {
67       OpusMetadata* meta = static_cast<OpusMetadata*>(metadata.get());
68       if (meta->mSamplingFrequency == 0 || meta->mChannels == 0 ||
69           meta->mIdHeader.IsEmpty()) {
70         bad = true;
71       }
72     }
73   }
74   if (bad) {
75     return NS_ERROR_FAILURE;
76   }
77 
78   // Storing
79   DebugOnly<bool> hasAudio = false;
80   DebugOnly<bool> hasVideo = false;
81   for (const RefPtr<TrackMetadataBase>& metadata : aMetadata) {
82     MOZ_ASSERT(metadata);
83 
84     if (metadata->GetKind() == TrackMetadataBase::METADATA_VP8) {
85       MOZ_ASSERT(!hasVideo);
86       VP8Metadata* meta = static_cast<VP8Metadata*>(metadata.get());
87       mEbmlComposer->SetVideoConfig(meta->mWidth, meta->mHeight,
88                                     meta->mDisplayWidth, meta->mDisplayHeight);
89       hasVideo = true;
90     }
91 
92     if (metadata->GetKind() == TrackMetadataBase::METADATA_VORBIS) {
93       MOZ_ASSERT(!hasAudio);
94       VorbisMetadata* meta = static_cast<VorbisMetadata*>(metadata.get());
95       mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels);
96       mEbmlComposer->SetAudioCodecPrivateData(meta->mData);
97       hasAudio = true;
98     }
99 
100     if (metadata->GetKind() == TrackMetadataBase::METADATA_OPUS) {
101       MOZ_ASSERT(!hasAudio);
102       OpusMetadata* meta = static_cast<OpusMetadata*>(metadata.get());
103       mEbmlComposer->SetAudioConfig(meta->mSamplingFrequency, meta->mChannels);
104       mEbmlComposer->SetAudioCodecPrivateData(meta->mIdHeader);
105       hasAudio = true;
106     }
107   }
108   mEbmlComposer->GenerateHeader();
109   return NS_OK;
110 }
111 
112 }  // namespace mozilla
113