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