AOMedia AV1 Codec
analyzer
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 #include <wx/wx.h>
12 #include <wx/aboutdlg.h>
13 #include <wx/cmdline.h>
14 #include <wx/dcbuffer.h>
15 
16 #include "aom/aom_decoder.h"
17 #include "aom/aomdx.h"
18 #include "av1/common/av1_common_int.h"
19 #include "av1/decoder/accounting.h"
20 #include "av1/decoder/inspection.h"
21 #include "common/tools_common.h"
22 #include "common/video_reader.h"
23 
24 #define OD_SIGNMASK(a) (-((a) < 0))
25 #define OD_FLIPSIGNI(a, b) (((a) + OD_SIGNMASK(b)) ^ OD_SIGNMASK(b))
26 #define OD_DIV_ROUND(x, y) (((x) + OD_FLIPSIGNI((y) >> 1, x)) / (y))
27 
28 enum {
29  OD_LUMA_MASK = 1 << 0,
30  OD_CB_MASK = 1 << 1,
31  OD_CR_MASK = 1 << 2,
32  OD_ALL_MASK = OD_LUMA_MASK | OD_CB_MASK | OD_CR_MASK
33 };
34 
35 class AV1Decoder {
36  private:
37  FILE *input;
38  wxString path;
39 
40  AvxVideoReader *reader;
41  const AvxVideoInfo *info;
42  aom_codec_iface_t *decoder;
43 
44  insp_frame_data frame_data;
45 
46  aom_codec_ctx_t codec;
47  bool show_padding;
48 
49  public:
50  aom_image_t *image;
51  int frame;
52 
53  int plane_mask;
54 
55  AV1Decoder();
56  ~AV1Decoder();
57 
58  bool open(const wxString &path);
59  void close();
60  bool step();
61 
62  int getWidthPadding() const;
63  int getHeightPadding() const;
64  void togglePadding();
65  int getWidth() const;
66  int getHeight() const;
67 
68  bool getAccountingStruct(Accounting **acct);
69  bool setInspectionCallback();
70 
71  static void inspect(void *decoder, void *data);
72 };
73 
74 AV1Decoder::AV1Decoder()
75  : reader(NULL), info(NULL), decoder(NULL), show_padding(false), image(NULL),
76  frame(0) {}
77 
78 AV1Decoder::~AV1Decoder() {}
79 
80 void AV1Decoder::togglePadding() { show_padding = !show_padding; }
81 
82 bool AV1Decoder::open(const wxString &path) {
83  reader = aom_video_reader_open(path.mb_str());
84  if (!reader) {
85  fprintf(stderr, "Failed to open %s for reading.", path.mb_str().data());
86  return false;
87  }
88  this->path = path;
89  info = aom_video_reader_get_info(reader);
90  decoder = get_aom_decoder_by_fourcc(info->codec_fourcc);
91  if (!decoder) {
92  fprintf(stderr, "Unknown input codec.");
93  return false;
94  }
95  printf("Using %s\n", aom_codec_iface_name(decoder));
96  if (aom_codec_dec_init(&codec, decoder, NULL, 0)) {
97  fprintf(stderr, "Failed to initialize decoder.");
98  return false;
99  }
100  ifd_init(&frame_data, info->frame_width, info->frame_height);
101  setInspectionCallback();
102  return true;
103 }
104 
105 void AV1Decoder::close() {}
106 
107 bool AV1Decoder::step() {
108  if (aom_video_reader_read_frame(reader)) {
109  size_t frame_size;
110  const unsigned char *frame_data;
111  frame_data = aom_video_reader_get_frame(reader, &frame_size);
112  if (aom_codec_decode(&codec, frame_data, frame_size, NULL)) {
113  fprintf(stderr, "Failed to decode frame.");
114  return false;
115  } else {
116  aom_codec_iter_t iter = NULL;
117  image = aom_codec_get_frame(&codec, &iter);
118  if (image != NULL) {
119  frame++;
120  return true;
121  }
122  return false;
123  }
124  }
125  return false;
126 }
127 
128 int AV1Decoder::getWidth() const {
129  return info->frame_width + 2 * getWidthPadding();
130 }
131 
132 int AV1Decoder::getWidthPadding() const {
133  return show_padding ? AOMMAX(info->frame_width + 16,
134  ALIGN_POWER_OF_TWO(info->frame_width, 6)) -
135  info->frame_width
136  : 0;
137 }
138 
139 int AV1Decoder::getHeight() const {
140  return info->frame_height + 2 * getHeightPadding();
141 }
142 
143 int AV1Decoder::getHeightPadding() const {
144  return show_padding ? AOMMAX(info->frame_height + 16,
145  ALIGN_POWER_OF_TWO(info->frame_height, 6)) -
146  info->frame_height
147  : 0;
148 }
149 
150 bool AV1Decoder::getAccountingStruct(Accounting **accounting) {
151  return aom_codec_control(&codec, AV1_GET_ACCOUNTING, accounting) ==
152  AOM_CODEC_OK;
153 }
154 
155 bool AV1Decoder::setInspectionCallback() {
156  aom_inspect_init ii;
157  ii.inspect_cb = AV1Decoder::inspect;
158  ii.inspect_ctx = (void *)this;
159  return aom_codec_control(&codec, AV1_SET_INSPECTION_CALLBACK, &ii) ==
160  AOM_CODEC_OK;
161 }
162 
163 void AV1Decoder::inspect(void *pbi, void *data) {
164  AV1Decoder *decoder = (AV1Decoder *)data;
165  ifd_inspect(&decoder->frame_data, pbi, 0);
166 }
167 
168 #define MIN_ZOOM (1)
169 #define MAX_ZOOM (4)
170 
171 class AnalyzerPanel : public wxPanel {
172  DECLARE_EVENT_TABLE()
173 
174  private:
175  AV1Decoder decoder;
176  const wxString path;
177 
178  int zoom;
179  unsigned char *pixels;
180 
181  const bool bit_accounting;
182  double *bpp_q3;
183 
184  int plane_mask;
185 
186  // The display size is the decode size, scaled by the zoom.
187  int getDisplayWidth() const;
188  int getDisplayHeight() const;
189 
190  bool updateDisplaySize();
191 
192  void computeBitsPerPixel();
193 
194  public:
195  AnalyzerPanel(wxWindow *parent, const wxString &path,
196  const bool bit_accounting);
197  ~AnalyzerPanel();
198 
199  bool open(const wxString &path);
200  void close();
201  void render();
202  void togglePadding();
203  bool nextFrame();
204  void refresh();
205 
206  int getZoom() const;
207  bool setZoom(int zoom);
208 
209  void setShowPlane(bool show_plane, int mask);
210 
211  void onPaint(wxPaintEvent &event); // NOLINT
212 };
213 
214 BEGIN_EVENT_TABLE(AnalyzerPanel, wxPanel)
215 EVT_PAINT(AnalyzerPanel::onPaint)
216 END_EVENT_TABLE()
217 
218 AnalyzerPanel::AnalyzerPanel(wxWindow *parent, const wxString &path,
219  const bool bit_accounting)
220  : wxPanel(parent), path(path), zoom(0), pixels(NULL),
221  bit_accounting(bit_accounting), bpp_q3(NULL), plane_mask(OD_ALL_MASK) {}
222 
223 AnalyzerPanel::~AnalyzerPanel() { close(); }
224 
225 void AnalyzerPanel::setShowPlane(bool show_plane, int mask) {
226  if (show_plane) {
227  plane_mask |= mask;
228  } else {
229  plane_mask &= ~mask;
230  }
231 }
232 
233 void AnalyzerPanel::render() {
234  aom_image_t *img = decoder.image;
235  const int hbd = !!(img->fmt & AOM_IMG_FMT_HIGHBITDEPTH);
236  int y_stride = img->stride[0] >> hbd;
237  int cb_stride = img->stride[1] >> hbd;
238  int cr_stride = img->stride[2] >> hbd;
239  int p_stride = 3 * getDisplayWidth();
240  unsigned char *y_row = img->planes[0];
241  unsigned char *cb_row = img->planes[1];
242  unsigned char *cr_row = img->planes[2];
243  uint16_t *y_row16 = reinterpret_cast<uint16_t *>(y_row);
244  uint16_t *cb_row16 = reinterpret_cast<uint16_t *>(cb_row);
245  uint16_t *cr_row16 = reinterpret_cast<uint16_t *>(cr_row);
246  unsigned char *p_row = pixels;
247  int y_width_padding = decoder.getWidthPadding();
248  int cb_width_padding = y_width_padding >> 1;
249  int cr_width_padding = y_width_padding >> 1;
250  int y_height_padding = decoder.getHeightPadding();
251  int cb_height_padding = y_height_padding >> 1;
252  int cr_height_padding = y_height_padding >> 1;
253  for (int j = 0; j < decoder.getHeight(); j++) {
254  unsigned char *y = y_row - y_stride * y_height_padding;
255  unsigned char *cb = cb_row - cb_stride * cb_height_padding;
256  unsigned char *cr = cr_row - cr_stride * cr_height_padding;
257  uint16_t *y16 = y_row16 - y_stride * y_height_padding;
258  uint16_t *cb16 = cb_row16 - cb_stride * cb_height_padding;
259  uint16_t *cr16 = cr_row16 - cr_stride * cr_height_padding;
260  unsigned char *p = p_row;
261  for (int i = 0; i < decoder.getWidth(); i++) {
262  int64_t yval;
263  int64_t cbval;
264  int64_t crval;
265  int pmask;
266  unsigned rval;
267  unsigned gval;
268  unsigned bval;
269  if (hbd) {
270  yval = *(y16 - y_width_padding);
271  cbval = *(cb16 - cb_width_padding);
272  crval = *(cr16 - cr_width_padding);
273  } else {
274  yval = *(y - y_width_padding);
275  cbval = *(cb - cb_width_padding);
276  crval = *(cr - cr_width_padding);
277  }
278  pmask = plane_mask;
279  if (pmask & OD_LUMA_MASK) {
280  yval -= 16;
281  } else {
282  yval = 128;
283  }
284  cbval = ((pmask & OD_CB_MASK) >> 1) * (cbval - 128);
285  crval = ((pmask & OD_CR_MASK) >> 2) * (crval - 128);
286  /*This is intentionally slow and very accurate.*/
287  rval = OD_CLAMPI(
288  0,
289  (int32_t)OD_DIV_ROUND(
290  2916394880000LL * yval + 4490222169144LL * crval, 9745792000LL),
291  65535);
292  gval = OD_CLAMPI(0,
293  (int32_t)OD_DIV_ROUND(2916394880000LL * yval -
294  534117096223LL * cbval -
295  1334761232047LL * crval,
296  9745792000LL),
297  65535);
298  bval = OD_CLAMPI(
299  0,
300  (int32_t)OD_DIV_ROUND(
301  2916394880000LL * yval + 5290866304968LL * cbval, 9745792000LL),
302  65535);
303  unsigned char *px_row = p;
304  for (int v = 0; v < zoom; v++) {
305  unsigned char *px = px_row;
306  for (int u = 0; u < zoom; u++) {
307  *(px + 0) = (unsigned char)(rval >> 8);
308  *(px + 1) = (unsigned char)(gval >> 8);
309  *(px + 2) = (unsigned char)(bval >> 8);
310  px += 3;
311  }
312  px_row += p_stride;
313  }
314  if (hbd) {
315  int dc = ((y16 - y_row16) & 1) | (1 - img->x_chroma_shift);
316  y16++;
317  cb16 += dc;
318  cr16 += dc;
319  } else {
320  int dc = ((y - y_row) & 1) | (1 - img->x_chroma_shift);
321  y++;
322  cb += dc;
323  cr += dc;
324  }
325  p += zoom * 3;
326  }
327  int dc = -((j & 1) | (1 - img->y_chroma_shift));
328  if (hbd) {
329  y_row16 += y_stride;
330  cb_row16 += dc & cb_stride;
331  cr_row16 += dc & cr_stride;
332  } else {
333  y_row += y_stride;
334  cb_row += dc & cb_stride;
335  cr_row += dc & cr_stride;
336  }
337  p_row += zoom * p_stride;
338  }
339 }
340 
341 void AnalyzerPanel::computeBitsPerPixel() {
342  Accounting *acct;
343  double bpp_total;
344  int totals_q3[MAX_SYMBOL_TYPES] = { 0 };
345  int sym_count[MAX_SYMBOL_TYPES] = { 0 };
346  decoder.getAccountingStruct(&acct);
347  for (int j = 0; j < decoder.getHeight(); j++) {
348  for (int i = 0; i < decoder.getWidth(); i++) {
349  bpp_q3[j * decoder.getWidth() + i] = 0.0;
350  }
351  }
352  bpp_total = 0;
353  for (int i = 0; i < acct->syms.num_syms; i++) {
354  AccountingSymbol *s;
355  s = &acct->syms.syms[i];
356  totals_q3[s->id] += s->bits;
357  sym_count[s->id] += s->samples;
358  }
359  printf("=== Frame: %-3i ===\n", decoder.frame - 1);
360  for (int i = 0; i < acct->syms.dictionary.num_strs; i++) {
361  if (totals_q3[i]) {
362  printf("%30s = %10.3f (%f bit/symbol)\n", acct->syms.dictionary.strs[i],
363  (float)totals_q3[i] / 8, (float)totals_q3[i] / 8 / sym_count[i]);
364  }
365  }
366  printf("\n");
367 }
368 
369 void AnalyzerPanel::togglePadding() {
370  decoder.togglePadding();
371  updateDisplaySize();
372 }
373 
374 bool AnalyzerPanel::nextFrame() {
375  if (decoder.step()) {
376  refresh();
377  return true;
378  }
379  return false;
380 }
381 
382 void AnalyzerPanel::refresh() {
383  if (bit_accounting) {
384  computeBitsPerPixel();
385  }
386  render();
387 }
388 
389 int AnalyzerPanel::getDisplayWidth() const { return zoom * decoder.getWidth(); }
390 
391 int AnalyzerPanel::getDisplayHeight() const {
392  return zoom * decoder.getHeight();
393 }
394 
395 bool AnalyzerPanel::updateDisplaySize() {
396  unsigned char *p = (unsigned char *)malloc(
397  sizeof(*p) * 3 * getDisplayWidth() * getDisplayHeight());
398  if (p == NULL) {
399  return false;
400  }
401  free(pixels);
402  pixels = p;
403  SetSize(getDisplayWidth(), getDisplayHeight());
404  return true;
405 }
406 
407 bool AnalyzerPanel::open(const wxString &path) {
408  if (!decoder.open(path)) {
409  return false;
410  }
411  if (!setZoom(MIN_ZOOM)) {
412  return false;
413  }
414  if (bit_accounting) {
415  bpp_q3 = (double *)malloc(sizeof(*bpp_q3) * decoder.getWidth() *
416  decoder.getHeight());
417  if (bpp_q3 == NULL) {
418  fprintf(stderr, "Could not allocate memory for bit accounting\n");
419  close();
420  return false;
421  }
422  }
423  if (!nextFrame()) {
424  close();
425  return false;
426  }
427  SetFocus();
428  return true;
429 }
430 
431 void AnalyzerPanel::close() {
432  decoder.close();
433  free(pixels);
434  pixels = NULL;
435  free(bpp_q3);
436  bpp_q3 = NULL;
437 }
438 
439 int AnalyzerPanel::getZoom() const { return zoom; }
440 
441 bool AnalyzerPanel::setZoom(int z) {
442  if (z <= MAX_ZOOM && z >= MIN_ZOOM && zoom != z) {
443  int old_zoom = zoom;
444  zoom = z;
445  if (!updateDisplaySize()) {
446  zoom = old_zoom;
447  return false;
448  }
449  return true;
450  }
451  return false;
452 }
453 
454 void AnalyzerPanel::onPaint(wxPaintEvent &) {
455  wxBitmap bmp(wxImage(getDisplayWidth(), getDisplayHeight(), pixels, true));
456  wxBufferedPaintDC dc(this, bmp);
457 }
458 
459 class AnalyzerFrame : public wxFrame {
460  DECLARE_EVENT_TABLE()
461 
462  private:
463  AnalyzerPanel *panel;
464  const bool bit_accounting;
465 
466  wxMenu *fileMenu;
467  wxMenu *viewMenu;
468  wxMenu *playbackMenu;
469 
470  public:
471  AnalyzerFrame(const bool bit_accounting); // NOLINT
472 
473  void onOpen(wxCommandEvent &event); // NOLINT
474  void onClose(wxCommandEvent &event); // NOLINT
475  void onQuit(wxCommandEvent &event); // NOLINT
476 
477  void onTogglePadding(wxCommandEvent &event); // NOLINT
478  void onZoomIn(wxCommandEvent &event); // NOLINT
479  void onZoomOut(wxCommandEvent &event); // NOLINT
480  void onActualSize(wxCommandEvent &event); // NOLINT
481 
482  void onToggleViewMenuCheckBox(wxCommandEvent &event); // NOLINT
483  void onResetAndToggleViewMenuCheckBox(wxCommandEvent &event); // NOLINT
484 
485  void onNextFrame(wxCommandEvent &event); // NOLINT
486  void onGotoFrame(wxCommandEvent &event); // NOLINT
487  void onRestart(wxCommandEvent &event); // NOLINT
488 
489  void onAbout(wxCommandEvent &event); // NOLINT
490 
491  bool open(const wxString &path);
492  bool setZoom(int zoom);
493  void updateViewMenu();
494 };
495 
496 enum {
497  wxID_NEXT_FRAME = 6000,
498  wxID_SHOW_Y,
499  wxID_SHOW_U,
500  wxID_SHOW_V,
501  wxID_GOTO_FRAME,
502  wxID_RESTART,
503  wxID_ACTUAL_SIZE,
504  wxID_PADDING
505 };
506 
507 BEGIN_EVENT_TABLE(AnalyzerFrame, wxFrame)
508 EVT_MENU(wxID_OPEN, AnalyzerFrame::onOpen)
509 EVT_MENU(wxID_CLOSE, AnalyzerFrame::onClose)
510 EVT_MENU(wxID_EXIT, AnalyzerFrame::onQuit)
511 EVT_MENU(wxID_PADDING, AnalyzerFrame::onTogglePadding)
512 EVT_MENU(wxID_ZOOM_IN, AnalyzerFrame::onZoomIn)
513 EVT_MENU(wxID_ZOOM_OUT, AnalyzerFrame::onZoomOut)
514 EVT_MENU(wxID_ACTUAL_SIZE, AnalyzerFrame::onActualSize)
515 EVT_MENU(wxID_SHOW_Y, AnalyzerFrame::onResetAndToggleViewMenuCheckBox)
516 EVT_MENU(wxID_SHOW_U, AnalyzerFrame::onResetAndToggleViewMenuCheckBox)
517 EVT_MENU(wxID_SHOW_V, AnalyzerFrame::onResetAndToggleViewMenuCheckBox)
518 EVT_MENU(wxID_NEXT_FRAME, AnalyzerFrame::onNextFrame)
519 EVT_MENU(wxID_GOTO_FRAME, AnalyzerFrame::onGotoFrame)
520 EVT_MENU(wxID_RESTART, AnalyzerFrame::onRestart)
521 EVT_MENU(wxID_ABOUT, AnalyzerFrame::onAbout)
522 END_EVENT_TABLE()
523 
524 AnalyzerFrame::AnalyzerFrame(const bool bit_accounting)
525  : wxFrame(NULL, wxID_ANY, _("AV1 Stream Analyzer"), wxDefaultPosition,
526  wxDefaultSize, wxDEFAULT_FRAME_STYLE),
527  panel(NULL), bit_accounting(bit_accounting) {
528  wxMenuBar *mb = new wxMenuBar();
529 
530  fileMenu = new wxMenu();
531  fileMenu->Append(wxID_OPEN, _("&Open...\tCtrl-O"), _("Open AV1 file"));
532  fileMenu->Append(wxID_CLOSE, _("&Close\tCtrl-W"), _("Close AV1 file"));
533  fileMenu->Enable(wxID_CLOSE, false);
534  fileMenu->Append(wxID_EXIT, _("E&xit\tCtrl-Q"), _("Quit this program"));
535  mb->Append(fileMenu, _("&File"));
536 
537  wxAcceleratorEntry entries[2];
538  entries[0].Set(wxACCEL_CTRL, (int)'=', wxID_ZOOM_IN);
539  entries[1].Set(wxACCEL_CTRL | wxACCEL_SHIFT, (int)'-', wxID_ZOOM_OUT);
540  wxAcceleratorTable accel(2, entries);
541  this->SetAcceleratorTable(accel);
542 
543  viewMenu = new wxMenu();
544  +viewMenu->Append(wxID_PADDING, _("Toggle padding\tCtrl-p"),
545  _("Show padding"));
546  viewMenu->Append(wxID_ZOOM_IN, _("Zoom-In\tCtrl-+"), _("Double image size"));
547  viewMenu->Append(wxID_ZOOM_OUT, _("Zoom-Out\tCtrl--"), _("Half image size"));
548  viewMenu->Append(wxID_ACTUAL_SIZE, _("Actual size\tCtrl-0"),
549  _("Actual size of the frame"));
550  viewMenu->AppendSeparator();
551  viewMenu->AppendCheckItem(wxID_SHOW_Y, _("&Y plane\tCtrl-Y"),
552  _("Show Y plane"));
553  viewMenu->AppendCheckItem(wxID_SHOW_U, _("&U plane\tCtrl-U"),
554  _("Show U plane"));
555  viewMenu->AppendCheckItem(wxID_SHOW_V, _("&V plane\tCtrl-V"),
556  _("Show V plane"));
557  mb->Append(viewMenu, _("&View"));
558 
559  playbackMenu = new wxMenu();
560  playbackMenu->Append(wxID_NEXT_FRAME, _("Next frame\tCtrl-."),
561  _("Go to next frame"));
562  /*playbackMenu->Append(wxID_RESTART, _("&Restart\tCtrl-R"),
563  _("Set video to frame 0"));
564  playbackMenu->Append(wxID_GOTO_FRAME, _("Jump to Frame\tCtrl-J"),
565  _("Go to frame number"));*/
566  mb->Append(playbackMenu, _("&Playback"));
567 
568  wxMenu *helpMenu = new wxMenu();
569  helpMenu->Append(wxID_ABOUT, _("&About...\tF1"), _("Show about dialog"));
570  mb->Append(helpMenu, _("&Help"));
571 
572  SetMenuBar(mb);
573 
574  CreateStatusBar(1);
575 }
576 
577 void AnalyzerFrame::onOpen(wxCommandEvent &WXUNUSED(event)) {
578  wxFileDialog openFileDialog(this, _("Open file"), wxEmptyString,
579  wxEmptyString, _("AV1 files (*.ivf)|*.ivf"),
580  wxFD_OPEN | wxFD_FILE_MUST_EXIST);
581  if (openFileDialog.ShowModal() != wxID_CANCEL) {
582  open(openFileDialog.GetPath());
583  }
584 }
585 
586 void AnalyzerFrame::onClose(wxCommandEvent &WXUNUSED(event)) {}
587 
588 void AnalyzerFrame::onQuit(wxCommandEvent &WXUNUSED(event)) { Close(true); }
589 
590 void AnalyzerFrame::onTogglePadding(wxCommandEvent &WXUNUSED(event)) {
591  panel->togglePadding();
592  SetClientSize(panel->GetSize());
593  panel->render();
594  panel->Refresh();
595 }
596 
597 void AnalyzerFrame::onZoomIn(wxCommandEvent &WXUNUSED(event)) {
598  setZoom(panel->getZoom() + 1);
599 }
600 
601 void AnalyzerFrame::onZoomOut(wxCommandEvent &WXUNUSED(event)) {
602  setZoom(panel->getZoom() - 1);
603 }
604 
605 void AnalyzerFrame::onActualSize(wxCommandEvent &WXUNUSED(event)) {
606  setZoom(MIN_ZOOM);
607 }
608 
609 void AnalyzerFrame::onToggleViewMenuCheckBox(wxCommandEvent &event) { // NOLINT
610  GetMenuBar()->Check(event.GetId(), event.IsChecked());
611  updateViewMenu();
612 }
613 
614 void AnalyzerFrame::onResetAndToggleViewMenuCheckBox(
615  wxCommandEvent &event) { // NOLINT
616  int id = event.GetId();
617  if (id != wxID_SHOW_Y && id != wxID_SHOW_U && id != wxID_SHOW_V) {
618  GetMenuBar()->Check(wxID_SHOW_Y, true);
619  GetMenuBar()->Check(wxID_SHOW_U, true);
620  GetMenuBar()->Check(wxID_SHOW_V, true);
621  }
622  onToggleViewMenuCheckBox(event);
623 }
624 
625 void AnalyzerFrame::onNextFrame(wxCommandEvent &WXUNUSED(event)) {
626  panel->nextFrame();
627  panel->Refresh(false);
628 }
629 
630 void AnalyzerFrame::onGotoFrame(wxCommandEvent &WXUNUSED(event)) {}
631 
632 void AnalyzerFrame::onRestart(wxCommandEvent &WXUNUSED(event)) {}
633 
634 void AnalyzerFrame::onAbout(wxCommandEvent &WXUNUSED(event)) {
635  wxAboutDialogInfo info;
636  info.SetName(_("AV1 Bitstream Analyzer"));
637  info.SetVersion(_("0.1-beta"));
638  info.SetDescription(
639  _("This program implements a bitstream analyzer for AV1"));
640  info.SetCopyright(
641  wxT("(C) 2017 Alliance for Open Media <negge@mozilla.com>"));
642  wxAboutBox(info);
643 }
644 
645 bool AnalyzerFrame::open(const wxString &path) {
646  panel = new AnalyzerPanel(this, path, bit_accounting);
647  if (panel->open(path)) {
648  SetClientSize(panel->GetSize());
649  return true;
650  } else {
651  delete panel;
652  return false;
653  }
654 }
655 
656 bool AnalyzerFrame::setZoom(int zoom) {
657  if (panel->setZoom(zoom)) {
658  GetMenuBar()->Enable(wxID_ACTUAL_SIZE, zoom != MIN_ZOOM);
659  GetMenuBar()->Enable(wxID_ZOOM_IN, zoom != MAX_ZOOM);
660  GetMenuBar()->Enable(wxID_ZOOM_OUT, zoom != MIN_ZOOM);
661  SetClientSize(panel->GetSize());
662  panel->render();
663  panel->Refresh();
664  return true;
665  }
666  return false;
667 }
668 
669 void AnalyzerFrame::updateViewMenu() {
670  panel->setShowPlane(GetMenuBar()->IsChecked(wxID_SHOW_Y), OD_LUMA_MASK);
671  panel->setShowPlane(GetMenuBar()->IsChecked(wxID_SHOW_U), OD_CB_MASK);
672  panel->setShowPlane(GetMenuBar()->IsChecked(wxID_SHOW_V), OD_CR_MASK);
673  SetClientSize(panel->GetSize());
674  panel->render();
675  panel->Refresh(false);
676 }
677 
678 class Analyzer : public wxApp {
679  private:
680  AnalyzerFrame *frame;
681 
682  public:
683  void OnInitCmdLine(wxCmdLineParser &parser); // NOLINT
684  bool OnCmdLineParsed(wxCmdLineParser &parser); // NOLINT
685 };
686 
687 static const wxCmdLineEntryDesc CMD_LINE_DESC[] = {
688  { wxCMD_LINE_SWITCH, _("h"), _("help"), _("Display this help and exit."),
689  wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
690  { wxCMD_LINE_SWITCH, _("a"), _("bit-accounting"), _("Enable bit accounting"),
691  wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL },
692  { wxCMD_LINE_PARAM, NULL, NULL, _("input.ivf"), wxCMD_LINE_VAL_STRING,
693  wxCMD_LINE_PARAM_OPTIONAL },
694  { wxCMD_LINE_NONE }
695 };
696 
697 void Analyzer::OnInitCmdLine(wxCmdLineParser &parser) { // NOLINT
698  parser.SetDesc(CMD_LINE_DESC);
699  parser.SetSwitchChars(_("-"));
700 }
701 
702 bool Analyzer::OnCmdLineParsed(wxCmdLineParser &parser) { // NOLINT
703  bool bit_accounting = parser.Found(_("a"));
704  if (bit_accounting && !CONFIG_ACCOUNTING) {
705  fprintf(stderr,
706  "Bit accounting support not found. "
707  "Recompile with:\n./cmake -DCONFIG_ACCOUNTING=1\n");
708  return false;
709  }
710  frame = new AnalyzerFrame(parser.Found(_("a")));
711  frame->Show();
712  if (parser.GetParamCount() > 0) {
713  return frame->open(parser.GetParam(0));
714  }
715  return true;
716 }
717 
718 void usage_exit(void) {
719  fprintf(stderr, "uhh\n");
720  exit(EXIT_FAILURE);
721 }
722 
723 IMPLEMENT_APP(Analyzer)
Operation completed without error.
Definition: aom_codec.h:157
aom_inspect_cb inspect_cb
Definition: aomdx.h:66
aom_image_t * aom_codec_get_frame(aom_codec_ctx_t *ctx, aom_codec_iter_t *iter)
Decoded frames iterator.
unsigned char * planes[3]
Definition: aom_image.h:215
Codec context structure.
Definition: aom_codec.h:298
#define AOM_IMG_FMT_HIGHBITDEPTH
Definition: aom_image.h:38
unsigned int y_chroma_shift
Definition: aom_image.h:206
Describes the decoder algorithm interface to applications.
Image Descriptor.
Definition: aom_image.h:182
aom_codec_err_t aom_codec_decode(aom_codec_ctx_t *ctx, const uint8_t *data, size_t data_sz, void *user_priv)
Decode data.
const struct aom_codec_iface aom_codec_iface_t
Codec interface structure.
Definition: aom_codec.h:254
#define aom_codec_dec_init(ctx, iface, cfg, flags)
Convenience macro for aom_codec_dec_init_ver()
Definition: aom_decoder.h:129
const char * aom_codec_iface_name(aom_codec_iface_t *iface)
Return the name for a given interface.
Codec control function to set an aom_inspect_cb callback that is invoked each time a frame is decoded...
Definition: aomdx.h:382
void * inspect_ctx
Definition: aomdx.h:69
Structure to hold inspection callback and context.
Definition: aomdx.h:64
const void * aom_codec_iter_t
Iterator.
Definition: aom_codec.h:288
unsigned int x_chroma_shift
Definition: aom_image.h:205
Provides definitions for using AOM or AV1 within the aom Decoder interface.
int stride[3]
Definition: aom_image.h:216
aom_codec_err_t aom_codec_control(aom_codec_ctx_t *ctx, int ctrl_id,...)
Algorithm Control.
aom_img_fmt_t fmt
Definition: aom_image.h:183
struct Accounting Accounting
Definition: aomdx.h:50
Codec control function to retrieve a pointer to the Accounting struct, takes Accounting** as paramete...
Definition: aomdx.h:290