blob: 6ae7df646f4472ded8aae39596288a11b768ec49 [file] [log] [blame]
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -07001/*
Yaowu Xu9c01aa12016-09-01 14:32:49 -07002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -07003 *
Yaowu Xu9c01aa12016-09-01 14:32:49 -07004 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
Johann123e8a62017-12-28 14:40:49 -080010 */
Yaowu Xu9c01aa12016-09-01 14:32:49 -070011
Tom Finegandd3e2a52018-05-23 14:33:09 -070012#include "common/webmenc.h"
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -070013
Tom Fineganbb8157b2018-09-20 15:33:11 -070014#include <stdio.h>
15
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -070016#include <string>
17
Tom Fineganec0833f2018-09-19 14:28:20 -070018#include "common/av1_config.h"
Tom Finegan4317ba52016-03-24 13:12:51 -070019#include "third_party/libwebm/mkvmuxer/mkvmuxer.h"
20#include "third_party/libwebm/mkvmuxer/mkvmuxerutil.h"
21#include "third_party/libwebm/mkvmuxer/mkvwriter.h"
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -070022
23namespace {
24const uint64_t kDebugTrackUid = 0xDEADBEEF;
25const int kVideoTrackNumber = 1;
26} // namespace
27
Tom Fineganbb8157b2018-09-20 15:33:11 -070028int write_webm_file_header(struct WebmOutputContext *webm_ctx,
29 aom_codec_ctx_t *encoder_ctx,
30 const aom_codec_enc_cfg_t *cfg,
31 stereo_format_t stereo_fmt, unsigned int fourcc,
32 const struct AvxRational *par) {
Vignesh Venkatasubramanian9441f102016-04-25 13:28:24 -070033 mkvmuxer::MkvWriter *const writer = new mkvmuxer::MkvWriter(webm_ctx->stream);
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -070034 mkvmuxer::Segment *const segment = new mkvmuxer::Segment();
Tom Fineganbb8157b2018-09-20 15:33:11 -070035 if (!writer || !segment) {
36 fprintf(stderr, "webmenc> mkvmuxer objects alloc failed, out of memory?\n");
37 return -1;
38 }
39
40 bool ok = segment->Init(writer);
41 if (!ok) {
42 fprintf(stderr, "webmenc> mkvmuxer Init failed.\n");
43 return -1;
44 }
45
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -070046 segment->set_mode(mkvmuxer::Segment::kFile);
47 segment->OutputCues(true);
48
49 mkvmuxer::SegmentInfo *const info = segment->GetSegmentInfo();
Tom Fineganbb8157b2018-09-20 15:33:11 -070050 if (!info) {
51 fprintf(stderr, "webmenc> Cannot retrieve Segment Info.\n");
52 return -1;
53 }
54
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -070055 const uint64_t kTimecodeScale = 1000000;
56 info->set_timecode_scale(kTimecodeScale);
Yaowu Xuf883b422016-08-30 14:01:10 -070057 std::string version = "aomenc";
Vignesh Venkatasubramanian9441f102016-04-25 13:28:24 -070058 if (!webm_ctx->debug) {
Yaowu Xuf883b422016-08-30 14:01:10 -070059 version.append(std::string(" ") + aom_codec_version_str());
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -070060 }
61 info->set_writing_app(version.c_str());
62
63 const uint64_t video_track_id =
64 segment->AddVideoTrack(static_cast<int>(cfg->g_w),
clang-format01f4c712016-08-12 15:10:25 -070065 static_cast<int>(cfg->g_h), kVideoTrackNumber);
66 mkvmuxer::VideoTrack *const video_track = static_cast<mkvmuxer::VideoTrack *>(
67 segment->GetTrackByNumber(video_track_id));
Tom Fineganec0833f2018-09-19 14:28:20 -070068
Tom Fineganbb8157b2018-09-20 15:33:11 -070069 if (!video_track) {
70 fprintf(stderr, "webmenc> Video track creation failed.\n");
71 return -1;
72 }
73
74 ok = false;
Tom Fineganec0833f2018-09-19 14:28:20 -070075 aom_fixed_buf_t *obu_sequence_header =
76 aom_codec_get_global_headers(encoder_ctx);
Tom Fineganbb8157b2018-09-20 15:33:11 -070077 if (obu_sequence_header) {
Tom Fineganec0833f2018-09-19 14:28:20 -070078 Av1Config av1_config;
79 if (get_av1config_from_obu(
80 reinterpret_cast<const uint8_t *>(obu_sequence_header->buf),
81 obu_sequence_header->sz, false, &av1_config) == 0) {
82 uint8_t av1_config_buffer[4] = { 0 };
83 size_t bytes_written = 0;
84 if (write_av1config(&av1_config, sizeof(av1_config_buffer),
85 &bytes_written, av1_config_buffer) == 0) {
Tom Fineganbb8157b2018-09-20 15:33:11 -070086 ok = video_track->SetCodecPrivate(av1_config_buffer,
87 sizeof(av1_config_buffer));
Tom Fineganec0833f2018-09-19 14:28:20 -070088 }
89 }
90 free(obu_sequence_header->buf);
91 free(obu_sequence_header);
92 }
Tom Fineganbb8157b2018-09-20 15:33:11 -070093 if (!ok) {
94 fprintf(stderr, "webmenc> Unable to set AV1 config.\n");
95 return -1;
Yaowu Xu3d1bb972015-08-14 12:30:10 -070096 }
Tom Fineganbb8157b2018-09-20 15:33:11 -070097
98 ok = video_track->SetStereoMode(stereo_fmt);
99 if (!ok) {
100 fprintf(stderr, "webmenc> Unable to set stereo mode.\n");
101 return -1;
102 }
103
104 if (fourcc != AV1_FOURCC) {
105 fprintf(stderr, "webmenc> Unsupported codec (unknown 4 CC).\n");
106 return -1;
107 }
108 video_track->set_codec_id("V_AV1");
109
Frank Galligan09acd262015-06-01 10:20:58 -0700110 if (par->numerator > 1 || par->denominator > 1) {
111 // TODO(fgalligan): Add support of DisplayUnit, Display Aspect Ratio type
112 // to WebM format.
clang-format01f4c712016-08-12 15:10:25 -0700113 const uint64_t display_width = static_cast<uint64_t>(
114 ((cfg->g_w * par->numerator * 1.0) / par->denominator) + .5);
Frank Galligan09acd262015-06-01 10:20:58 -0700115 video_track->set_display_width(display_width);
116 video_track->set_display_height(cfg->g_h);
117 }
Tom Fineganbb8157b2018-09-20 15:33:11 -0700118
Vignesh Venkatasubramanian9441f102016-04-25 13:28:24 -0700119 if (webm_ctx->debug) {
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -0700120 video_track->set_uid(kDebugTrackUid);
121 }
Tom Fineganbb8157b2018-09-20 15:33:11 -0700122
Vignesh Venkatasubramanian9441f102016-04-25 13:28:24 -0700123 webm_ctx->writer = writer;
124 webm_ctx->segment = segment;
Tom Fineganbb8157b2018-09-20 15:33:11 -0700125
126 return 0;
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -0700127}
128
Tom Fineganbb8157b2018-09-20 15:33:11 -0700129int write_webm_block(struct WebmOutputContext *webm_ctx,
130 const aom_codec_enc_cfg_t *cfg,
131 const aom_codec_cx_pkt_t *pkt) {
132 if (!webm_ctx->segment) {
133 fprintf(stderr, "webmenc> segment is NULL.\n");
134 return -1;
135 }
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -0700136 mkvmuxer::Segment *const segment =
clang-format01f4c712016-08-12 15:10:25 -0700137 reinterpret_cast<mkvmuxer::Segment *>(webm_ctx->segment);
138 int64_t pts_ns = pkt->data.frame.pts * 1000000000ll * cfg->g_timebase.num /
139 cfg->g_timebase.den;
140 if (pts_ns <= webm_ctx->last_pts_ns) pts_ns = webm_ctx->last_pts_ns + 1000000;
Vignesh Venkatasubramanian9441f102016-04-25 13:28:24 -0700141 webm_ctx->last_pts_ns = pts_ns;
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -0700142
Tom Fineganbb8157b2018-09-20 15:33:11 -0700143 if (!segment->AddFrame(static_cast<uint8_t *>(pkt->data.frame.buf),
144 pkt->data.frame.sz, kVideoTrackNumber, pts_ns,
145 pkt->data.frame.flags & AOM_FRAME_IS_KEY)) {
146 fprintf(stderr, "webmenc> AddFrame failed.\n");
147 return -1;
148 }
149 return 0;
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -0700150}
151
Tom Fineganbb8157b2018-09-20 15:33:11 -0700152int write_webm_file_footer(struct WebmOutputContext *webm_ctx) {
153 if (!webm_ctx->writer || !webm_ctx->segment) {
154 fprintf(stderr, "webmenc> segment or writer NULL.\n");
155 return -1;
156 }
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -0700157 mkvmuxer::MkvWriter *const writer =
clang-format01f4c712016-08-12 15:10:25 -0700158 reinterpret_cast<mkvmuxer::MkvWriter *>(webm_ctx->writer);
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -0700159 mkvmuxer::Segment *const segment =
clang-format01f4c712016-08-12 15:10:25 -0700160 reinterpret_cast<mkvmuxer::Segment *>(webm_ctx->segment);
Tom Fineganbb8157b2018-09-20 15:33:11 -0700161 const bool ok = segment->Finalize();
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -0700162 delete segment;
163 delete writer;
Vignesh Venkatasubramanian9441f102016-04-25 13:28:24 -0700164 webm_ctx->writer = NULL;
165 webm_ctx->segment = NULL;
Tom Fineganbb8157b2018-09-20 15:33:11 -0700166
167 if (!ok) {
168 fprintf(stderr, "webmenc> Segment::Finalize failed.\n");
169 return -1;
170 }
171
172 return 0;
Vignesh Venkatasubramanian2dcbf8c2014-03-19 11:56:02 -0700173}