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