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