1 /*
2  * Copyright (c) 2017, Alliance for Open Media. All rights reserved
3  *
4  * 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.
10  */
11 
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include <memory>
16 #include <string>
17 
18 #include "config/aom_config.h"
19 
20 #include "common/ivfdec.h"
21 #include "common/obudec.h"
22 #include "common/tools_common.h"
23 #include "common/webmdec.h"
24 #include "tools/obu_parser.h"
25 
26 namespace {
27 
28 const size_t kInitialBufferSize = 100 * 1024;
29 
30 struct InputContext {
31   InputContext() = default;
~InputContext__anon0d40a1890111::InputContext32   ~InputContext() { free(unit_buffer); }
33 
Init__anon0d40a1890111::InputContext34   void Init() {
35     memset(avx_ctx, 0, sizeof(*avx_ctx));
36     memset(obu_ctx, 0, sizeof(*obu_ctx));
37     obu_ctx->avx_ctx = avx_ctx;
38 #if CONFIG_WEBM_IO
39     memset(webm_ctx, 0, sizeof(*webm_ctx));
40 #endif
41   }
42 
43   AvxInputContext *avx_ctx = nullptr;
44   ObuDecInputContext *obu_ctx = nullptr;
45 #if CONFIG_WEBM_IO
46   WebmInputContext *webm_ctx = nullptr;
47 #endif
48   uint8_t *unit_buffer = nullptr;
49   size_t unit_buffer_size = 0;
50 };
51 
PrintUsage()52 void PrintUsage() {
53   printf("Libaom OBU dump.\nUsage: dump_obu <input_file>\n");
54 }
55 
GetFileType(InputContext * ctx)56 VideoFileType GetFileType(InputContext *ctx) {
57   if (file_is_ivf(ctx->avx_ctx)) return FILE_TYPE_IVF;
58   if (file_is_obu(ctx->obu_ctx)) return FILE_TYPE_OBU;
59 #if CONFIG_WEBM_IO
60   if (file_is_webm(ctx->webm_ctx, ctx->avx_ctx)) return FILE_TYPE_WEBM;
61 #endif
62   return FILE_TYPE_RAW;
63 }
64 
ReadTemporalUnit(InputContext * ctx,size_t * unit_size)65 bool ReadTemporalUnit(InputContext *ctx, size_t *unit_size) {
66   const VideoFileType file_type = ctx->avx_ctx->file_type;
67   switch (file_type) {
68     case FILE_TYPE_IVF: {
69       if (ivf_read_frame(ctx->avx_ctx->file, &ctx->unit_buffer, unit_size,
70                          &ctx->unit_buffer_size, NULL)) {
71         return false;
72       }
73       break;
74     }
75     case FILE_TYPE_OBU: {
76       if (obudec_read_temporal_unit(ctx->obu_ctx, &ctx->unit_buffer, unit_size,
77                                     &ctx->unit_buffer_size)) {
78         return false;
79       }
80       break;
81     }
82 #if CONFIG_WEBM_IO
83     case FILE_TYPE_WEBM: {
84       if (webm_read_frame(ctx->webm_ctx, &ctx->unit_buffer, unit_size,
85                           &ctx->unit_buffer_size)) {
86         return false;
87       }
88       break;
89     }
90 #endif
91     default:
92       // TODO(tomfinegan): Abuse FILE_TYPE_RAW for AV1/OBU elementary streams?
93       fprintf(stderr, "Error: Unsupported file type.\n");
94       return false;
95   }
96 
97   return true;
98 }
99 
100 }  // namespace
101 
main(int argc,const char * argv[])102 int main(int argc, const char *argv[]) {
103   // TODO(tomfinegan): Could do with some params for verbosity.
104   if (argc < 2) {
105     PrintUsage();
106     return EXIT_SUCCESS;
107   }
108 
109   const std::string filename = argv[1];
110 
111   using FilePtr = std::unique_ptr<FILE, decltype(&fclose)>;
112   FilePtr input_file(fopen(filename.c_str(), "rb"), &fclose);
113   if (input_file.get() == nullptr) {
114     input_file.release();
115     fprintf(stderr, "Error: Cannot open input file.\n");
116     return EXIT_FAILURE;
117   }
118 
119   AvxInputContext avx_ctx;
120   InputContext input_ctx;
121   input_ctx.avx_ctx = &avx_ctx;
122   ObuDecInputContext obu_ctx;
123   input_ctx.obu_ctx = &obu_ctx;
124 #if CONFIG_WEBM_IO
125   WebmInputContext webm_ctx;
126   input_ctx.webm_ctx = &webm_ctx;
127 #endif
128 
129   input_ctx.Init();
130   avx_ctx.file = input_file.get();
131   avx_ctx.file_type = GetFileType(&input_ctx);
132 
133   // Note: the reader utilities will realloc the buffer using realloc() etc.
134   // Can't have nice things like unique_ptr wrappers with that type of
135   // behavior underneath the function calls.
136   input_ctx.unit_buffer =
137       reinterpret_cast<uint8_t *>(calloc(kInitialBufferSize, 1));
138   if (!input_ctx.unit_buffer) {
139     fprintf(stderr, "Error: No memory, can't alloc input buffer.\n");
140     return EXIT_FAILURE;
141   }
142   input_ctx.unit_buffer_size = kInitialBufferSize;
143 
144   size_t unit_size = 0;
145   int unit_number = 0;
146   int64_t obu_overhead_bytes_total = 0;
147   while (ReadTemporalUnit(&input_ctx, &unit_size)) {
148     printf("Temporal unit %d\n", unit_number);
149 
150     int obu_overhead_current_unit = 0;
151     if (!aom_tools::DumpObu(input_ctx.unit_buffer, static_cast<int>(unit_size),
152                             &obu_overhead_current_unit)) {
153       fprintf(stderr, "Error: Temporal Unit parse failed on unit number %d.\n",
154               unit_number);
155       return EXIT_FAILURE;
156     }
157     printf("  OBU overhead:    %d\n", obu_overhead_current_unit);
158     ++unit_number;
159     obu_overhead_bytes_total += obu_overhead_current_unit;
160   }
161 
162   printf("File total OBU overhead: %" PRId64 "\n", obu_overhead_bytes_total);
163   return EXIT_SUCCESS;
164 }
165