123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- /*
- * Copyright (c) 2016, Alliance for Open Media. All rights reserved
- *
- * This source code is subject to the terms of the BSD 2 Clause License and
- * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
- * was not distributed with this source code in the LICENSE file, you can
- * obtain it at www.aomedia.org/license/software. If the Alliance for Open
- * Media Patent License 1.0 was not distributed with this source code in the
- * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
- */
- #include "common/webmenc.h"
- #include <stdio.h>
- #include <string.h>
- #include <memory>
- #include <new>
- #include <string>
- #include "common/av1_config.h"
- #include "third_party/libwebm/mkvmuxer/mkvmuxer.h"
- #include "third_party/libwebm/mkvmuxer/mkvmuxerutil.h"
- #include "third_party/libwebm/mkvmuxer/mkvwriter.h"
- namespace {
- const uint64_t kDebugTrackUid = 0xDEADBEEF;
- const int kVideoTrackNumber = 1;
- // Simplistic mechanism to detect if an argv parameter refers to
- // an input or output file. Returns the total number of arguments that
- // should be skipped.
- int skip_input_output_arg(const char *arg, const char *input_fname) {
- if (strcmp(arg, input_fname) == 0) {
- return 1;
- }
- if (strcmp(arg, "-o") == 0 || strcmp(arg, "--output") == 0) {
- return 2;
- }
- if (strncmp(arg, "--output=", strlen("--output=")) == 0) {
- return 1;
- }
- return 0;
- }
- } // namespace
- char *extract_encoder_settings(const char *version, const char **argv, int argc,
- const char *input_fname) {
- // + 9 for "version:" prefix and for null terminator.
- size_t total_size = strlen(version) + 9;
- int i = 1;
- while (i < argc) {
- int num_skip = skip_input_output_arg(argv[i], input_fname);
- i += num_skip;
- if (num_skip == 0) {
- total_size += strlen(argv[i]) + 1; // + 1 is for space separator.
- ++i;
- }
- }
- char *result = static_cast<char *>(malloc(total_size));
- if (result == nullptr) {
- return nullptr;
- }
- char *cur = result;
- cur += snprintf(cur, total_size, "version:%s", version);
- i = 1;
- while (i < argc) {
- int num_skip = skip_input_output_arg(argv[i], input_fname);
- i += num_skip;
- if (num_skip == 0) {
- cur += snprintf(cur, total_size, " %s", argv[i]);
- ++i;
- }
- }
- *cur = '\0';
- return result;
- }
- int write_webm_file_header(struct WebmOutputContext *webm_ctx,
- aom_codec_ctx_t *encoder_ctx,
- const aom_codec_enc_cfg_t *cfg,
- stereo_format_t stereo_fmt, unsigned int fourcc,
- const struct AvxRational *par,
- const char *encoder_settings) {
- std::unique_ptr<mkvmuxer::MkvWriter> writer(
- new (std::nothrow) mkvmuxer::MkvWriter(webm_ctx->stream));
- std::unique_ptr<mkvmuxer::Segment> segment(new (std::nothrow)
- mkvmuxer::Segment());
- if (writer == nullptr || segment == nullptr) {
- fprintf(stderr, "webmenc> mkvmuxer objects alloc failed, out of memory?\n");
- return -1;
- }
- bool ok = segment->Init(writer.get());
- if (!ok) {
- fprintf(stderr, "webmenc> mkvmuxer Init failed.\n");
- return -1;
- }
- segment->set_mode(mkvmuxer::Segment::kFile);
- segment->OutputCues(true);
- mkvmuxer::SegmentInfo *const info = segment->GetSegmentInfo();
- if (!info) {
- fprintf(stderr, "webmenc> Cannot retrieve Segment Info.\n");
- return -1;
- }
- const uint64_t kTimecodeScale = 1000000;
- info->set_timecode_scale(kTimecodeScale);
- std::string version = "aomenc";
- if (!webm_ctx->debug) {
- version.append(std::string(" ") + aom_codec_version_str());
- }
- info->set_writing_app(version.c_str());
- const uint64_t video_track_id =
- segment->AddVideoTrack(static_cast<int>(cfg->g_w),
- static_cast<int>(cfg->g_h), kVideoTrackNumber);
- mkvmuxer::VideoTrack *const video_track = static_cast<mkvmuxer::VideoTrack *>(
- segment->GetTrackByNumber(video_track_id));
- if (!video_track) {
- fprintf(stderr, "webmenc> Video track creation failed.\n");
- return -1;
- }
- ok = false;
- aom_fixed_buf_t *obu_sequence_header =
- aom_codec_get_global_headers(encoder_ctx);
- if (obu_sequence_header) {
- Av1Config av1_config;
- if (get_av1config_from_obu(
- reinterpret_cast<const uint8_t *>(obu_sequence_header->buf),
- obu_sequence_header->sz, false, &av1_config) == 0) {
- uint8_t av1_config_buffer[4] = { 0 };
- size_t bytes_written = 0;
- if (write_av1config(&av1_config, sizeof(av1_config_buffer),
- &bytes_written, av1_config_buffer) == 0) {
- ok = video_track->SetCodecPrivate(av1_config_buffer,
- sizeof(av1_config_buffer));
- }
- }
- free(obu_sequence_header->buf);
- free(obu_sequence_header);
- }
- if (!ok) {
- fprintf(stderr, "webmenc> Unable to set AV1 config.\n");
- return -1;
- }
- ok = video_track->SetStereoMode(stereo_fmt);
- if (!ok) {
- fprintf(stderr, "webmenc> Unable to set stereo mode.\n");
- return -1;
- }
- if (fourcc != AV1_FOURCC) {
- fprintf(stderr, "webmenc> Unsupported codec (unknown 4 CC).\n");
- return -1;
- }
- video_track->set_codec_id("V_AV1");
- if (par->numerator > 1 || par->denominator > 1) {
- // TODO(fgalligan): Add support of DisplayUnit, Display Aspect Ratio type
- // to WebM format.
- const uint64_t display_width = static_cast<uint64_t>(
- ((cfg->g_w * par->numerator * 1.0) / par->denominator) + .5);
- video_track->set_display_width(display_width);
- video_track->set_display_height(cfg->g_h);
- }
- if (encoder_settings != nullptr) {
- mkvmuxer::Tag *tag = segment->AddTag();
- if (tag == nullptr) {
- fprintf(stderr,
- "webmenc> Unable to allocate memory for encoder settings tag.\n");
- return -1;
- }
- ok = tag->add_simple_tag("ENCODER_SETTINGS", encoder_settings);
- if (!ok) {
- fprintf(stderr,
- "webmenc> Unable to allocate memory for encoder settings tag.\n");
- return -1;
- }
- }
- if (webm_ctx->debug) {
- video_track->set_uid(kDebugTrackUid);
- }
- webm_ctx->writer = writer.release();
- webm_ctx->segment = segment.release();
- return 0;
- }
- int write_webm_block(struct WebmOutputContext *webm_ctx,
- const aom_codec_enc_cfg_t *cfg,
- const aom_codec_cx_pkt_t *pkt) {
- if (!webm_ctx->segment) {
- fprintf(stderr, "webmenc> segment is NULL.\n");
- return -1;
- }
- mkvmuxer::Segment *const segment =
- reinterpret_cast<mkvmuxer::Segment *>(webm_ctx->segment);
- int64_t pts_ns = pkt->data.frame.pts * 1000000000ll * cfg->g_timebase.num /
- cfg->g_timebase.den;
- if (pts_ns <= webm_ctx->last_pts_ns) pts_ns = webm_ctx->last_pts_ns + 1000000;
- webm_ctx->last_pts_ns = pts_ns;
- if (!segment->AddFrame(static_cast<uint8_t *>(pkt->data.frame.buf),
- pkt->data.frame.sz, kVideoTrackNumber, pts_ns,
- pkt->data.frame.flags & AOM_FRAME_IS_KEY)) {
- fprintf(stderr, "webmenc> AddFrame failed.\n");
- return -1;
- }
- return 0;
- }
- int write_webm_file_footer(struct WebmOutputContext *webm_ctx) {
- if (!webm_ctx->writer || !webm_ctx->segment) {
- fprintf(stderr, "webmenc> segment or writer NULL.\n");
- return -1;
- }
- mkvmuxer::MkvWriter *const writer =
- reinterpret_cast<mkvmuxer::MkvWriter *>(webm_ctx->writer);
- mkvmuxer::Segment *const segment =
- reinterpret_cast<mkvmuxer::Segment *>(webm_ctx->segment);
- const bool ok = segment->Finalize();
- delete segment;
- delete writer;
- webm_ctx->writer = NULL;
- webm_ctx->segment = NULL;
- if (!ok) {
- fprintf(stderr, "webmenc> Segment::Finalize failed.\n");
- return -1;
- }
- return 0;
- }
|