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/onyxc_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 const AvxInterface *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->codec_interface())); 96 if (aom_codec_dec_init(&codec, decoder->codec_interface(), 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 daala file")); 532 fileMenu->Append(wxID_CLOSE, _("&Close\tCtrl-W"), _("Close daala 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 (at) 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) 724