1 /*
2  * vp8parser-test.c - Print IVF/VP8 headers
3  *
4  * Copyright (C) 2013-2014 Intel Corporation
5  *   Author: Halley Zhao <halley.zhao@intel.com>
6  *   Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <gst/gst.h>
28 #include <gst/base/gstbytereader.h>
29 #include <gst/codecparsers/gstvp8parser.h>
30 
31 #define FOURCC_VP80             GST_MAKE_FOURCC('V','P','8','0')
32 #define IVF_FILE_HDR_SIZE       32
33 #define IVF_FRAME_HDR_SIZE      12
34 
35 /* Maximum VP8 Frame Header size in bits */
36 #define VP8_FRAME_HDR_SIZE      10127
37 
38 typedef struct _IVFFileHdr IVFFileHdr;
39 struct _IVFFileHdr
40 {
41   guint16 version;
42   guint16 length;
43   guint32 fourcc;
44   guint16 width;
45   guint16 height;
46   guint32 framerate;
47   guint32 time_scale;
48   guint32 num_frames;
49 };
50 
51 typedef struct _IVFFrameHdr IVFFrameHdr;
52 struct _IVFFrameHdr
53 {
54   guint32 frame_size;
55   guint64 timestamp;
56 };
57 
58 static gboolean
parse_ivf_file_header(IVFFileHdr * ivf_hdr,guint8 * data,guint size)59 parse_ivf_file_header (IVFFileHdr * ivf_hdr, guint8 * data, guint size)
60 {
61   GstByteReader br;
62 
63   if (size < IVF_FILE_HDR_SIZE) {
64     g_warning ("size is smaller than IVF file header");
65     goto error;
66   }
67 
68   g_assert (data[0] == 'D' && data[1] == 'K' && data[2] == 'I'
69       && data[3] == 'F');
70 
71   gst_byte_reader_init (&br, data, size);
72   gst_byte_reader_skip (&br, 4);
73 
74   if (!gst_byte_reader_get_uint16_le (&br, &ivf_hdr->version))
75     goto error;
76   g_assert (ivf_hdr->version == 0);
77 
78   if (!gst_byte_reader_get_uint16_le (&br, &ivf_hdr->length))
79     goto error;
80   g_assert (ivf_hdr->length == 0x20);
81 
82   if (!gst_byte_reader_get_uint32_le (&br, &ivf_hdr->fourcc))
83     goto error;
84   g_assert (ivf_hdr->fourcc == FOURCC_VP80);
85 
86   if (!gst_byte_reader_get_uint16_le (&br, &ivf_hdr->width))
87     goto error;
88   if (!gst_byte_reader_get_uint16_le (&br, &ivf_hdr->height))
89     goto error;
90   if (!gst_byte_reader_get_uint32_le (&br, &ivf_hdr->framerate))
91     goto error;
92   if (!gst_byte_reader_get_uint32_le (&br, &ivf_hdr->time_scale))
93     goto error;
94   if (!gst_byte_reader_get_uint32_le (&br, &ivf_hdr->num_frames))
95     goto error;
96 
97   g_print ("IVF File Information:\n");
98   g_print ("  %-32s : %u\n", "version", ivf_hdr->version);
99   g_print ("  %-32s : %u\n", "length", ivf_hdr->length);
100   g_print ("  %-32s : '%" GST_FOURCC_FORMAT "'\n", "fourcc",
101       GST_FOURCC_ARGS (ivf_hdr->fourcc));
102   g_print ("  %-32s : %u\n", "width", ivf_hdr->width);
103   g_print ("  %-32s : %u\n", "height", ivf_hdr->height);
104   g_print ("  %-32s : %u\n", "framerate", ivf_hdr->framerate);
105   g_print ("  %-32s : %u\n", "time_scale", ivf_hdr->time_scale);
106   g_print ("  %-32s : %u\n", "num_frames", ivf_hdr->num_frames);
107   g_print ("\n");
108 
109   return TRUE;
110 
111 error:
112   return FALSE;
113 }
114 
115 static gboolean
parse_ivf_frame_header(IVFFrameHdr * frm_hdr,guint8 * data,guint size)116 parse_ivf_frame_header (IVFFrameHdr * frm_hdr, guint8 * data, guint size)
117 {
118   GstByteReader br;
119 
120   if (size < IVF_FRAME_HDR_SIZE) {
121     g_warning ("size is smaller than IVF frame header");
122     goto error;
123   }
124 
125   gst_byte_reader_init (&br, data, size);
126   if (!gst_byte_reader_get_uint32_le (&br, &frm_hdr->frame_size))
127     goto error;
128   if (!gst_byte_reader_get_uint64_le (&br, &frm_hdr->timestamp))
129     goto error;
130 
131   g_print ("IVF Frame Information:\n");
132   g_print ("  %-32s : %u\n", "size", frm_hdr->frame_size);
133   g_print ("  %-32s : %" G_GINT64_FORMAT " \n", "timestamp",
134       frm_hdr->timestamp);
135   g_print ("\n");
136 
137   return TRUE;
138 
139 error:
140   return FALSE;
141 }
142 
143 static void
print_segmentation(GstVp8Segmentation * seg)144 print_segmentation (GstVp8Segmentation * seg)
145 {
146   gint i;
147 
148   g_print ("+ Segmentation:\n");
149   g_print ("  %-32s : %d\n", "segmentation_enabled", seg->segmentation_enabled);
150   g_print ("  %-32s : %d\n", "update_mb_segmentation_map",
151       seg->update_mb_segmentation_map);
152   g_print ("  %-32s : %d\n", "update_segment_feature_data",
153       seg->update_segment_feature_data);
154 
155   if (seg->update_segment_feature_data) {
156     g_print ("  %-32s : %d\n", "segment_feature_mode",
157         seg->segment_feature_mode);
158     g_print ("  %-32s : %d", "quantizer_update_value",
159         seg->quantizer_update_value[0]);
160     for (i = 1; i < 4; i++) {
161       g_print (", %d", seg->quantizer_update_value[i]);
162     }
163     g_print ("\n");
164     g_print ("  %-32s : %d", "lf_update_value", seg->lf_update_value[0]);
165     for (i = 1; i < 4; i++) {
166       g_print (", %d", seg->lf_update_value[i]);
167     }
168     g_print ("\n");
169   }
170 
171   if (seg->update_mb_segmentation_map) {
172     g_print ("  %-32s : %d", "segment_prob", seg->segment_prob[0]);
173     for (i = 1; i < 3; i++) {
174       g_print (", %d", seg->segment_prob[i]);
175     }
176     g_print ("\n");
177   }
178 }
179 
180 static void
print_mb_lf_adjustments(GstVp8MbLfAdjustments * adj)181 print_mb_lf_adjustments (GstVp8MbLfAdjustments * adj)
182 {
183   gint i;
184 
185   g_print ("+ MB Loop-Filter Adjustments:\n");
186   g_print ("  %-32s : %d\n", "loop_filter_adj_enable",
187       adj->loop_filter_adj_enable);
188   if (adj->loop_filter_adj_enable) {
189     g_print ("  %-32s : %d\n", "mode_ref_lf_delta_update",
190         adj->mode_ref_lf_delta_update);
191     if (adj->mode_ref_lf_delta_update) {
192       g_print ("  %-32s : %d", "ref_frame_delta", adj->ref_frame_delta[0]);
193       for (i = 1; i < 4; i++) {
194         g_print (", %d", adj->ref_frame_delta[i]);
195       }
196       g_print ("\n");
197       g_print ("  %-32s : %d", "mb_mode_delta", adj->mb_mode_delta[0]);
198       for (i = 1; i < 4; i++) {
199         g_print (", %d", adj->mb_mode_delta[i]);
200       }
201       g_print ("\n");
202     }
203   }
204 }
205 
206 static void
print_quant_indices(GstVp8QuantIndices * qip)207 print_quant_indices (GstVp8QuantIndices * qip)
208 {
209   g_print ("+ Dequantization Indices:\n");
210   g_print ("  %-32s : %d\n", "y_ac_qi", qip->y_ac_qi);
211   g_print ("  %-32s : %d\n", "y_dc_delta", qip->y_dc_delta);
212   g_print ("  %-32s : %d\n", "y2_dc_delta", qip->y2_dc_delta);
213   g_print ("  %-32s : %d\n", "y2_ac_delta", qip->y2_ac_delta);
214   g_print ("  %-32s : %d\n", "uv_dc_delta", qip->uv_dc_delta);
215   g_print ("  %-32s : %d\n", "uv_ac_delta", qip->uv_ac_delta);
216 }
217 
218 static void
print_mv_probs(GstVp8MvProbs * probs)219 print_mv_probs (GstVp8MvProbs * probs)
220 {
221   gint i, j;
222 
223   g_print ("+ MV Probabilities:\n");
224   for (j = 0; j < 2; j++) {
225     g_print ("  %-32s : %d", j == 0 ? "row" : "column", probs->prob[j][0]);
226     for (i = 1; i < 19; i++) {
227       g_print (", %d", probs->prob[j][i]);
228     }
229     g_print ("\n");
230   }
231 }
232 
233 static void
print_mode_probs(GstVp8ModeProbs * probs)234 print_mode_probs (GstVp8ModeProbs * probs)
235 {
236   gint i;
237 
238   g_print ("+ Intra-mode Probabilities:\n");
239   g_print ("  %-32s : %d", "luma", probs->y_prob[0]);
240   for (i = 1; i < 4; i++) {
241     g_print (", %d", probs->y_prob[i]);
242   }
243   g_print ("\n");
244   g_print ("  %-32s : %d", "chroma", probs->uv_prob[0]);
245   for (i = 1; i < 3; i++) {
246     g_print (", %d", probs->uv_prob[i]);
247   }
248   g_print ("\n");
249 }
250 
251 static void
print_frame_header(GstVp8FrameHdr * frame_hdr)252 print_frame_header (GstVp8FrameHdr * frame_hdr)
253 {
254   g_print ("  %-32s : %d\n", "key_frame", frame_hdr->key_frame);
255   g_print ("  %-32s : %d\n", "version", frame_hdr->version);
256   g_print ("  %-32s : %d\n", "show_frame", frame_hdr->show_frame);
257   g_print ("  %-32s : %d\n", "first_part_size", frame_hdr->first_part_size);
258   if (frame_hdr->key_frame) {
259     g_print ("  %-32s : %d\n", "width", frame_hdr->width);
260     g_print ("  %-32s : %d\n", "height", frame_hdr->height);
261     g_print ("  %-32s : %d\n", "horizontal_scale", frame_hdr->horiz_scale_code);
262     g_print ("  %-32s : %d\n", "vertical_scale", frame_hdr->vert_scale_code);
263   }
264 
265   if (frame_hdr->key_frame) {
266     g_print ("  %-32s : %d\n", "color_space", frame_hdr->color_space);
267     g_print ("  %-32s : %d\n", "clamping_type", frame_hdr->clamping_type);
268   }
269 
270   g_print ("  %-32s : %d\n", "filter_type", frame_hdr->filter_type);
271   g_print ("  %-32s : %d\n", "loop_filter_level", frame_hdr->loop_filter_level);
272   g_print ("  %-32s : %d\n", "sharpness_level", frame_hdr->sharpness_level);
273 
274   g_print ("  %-32s : %d\n", "log2_nbr_of_dct_partitions",
275       frame_hdr->log2_nbr_of_dct_partitions);
276 
277   if (frame_hdr->key_frame) {
278     g_print ("  %-32s : %d\n", "refresh_entropy_probs",
279         frame_hdr->refresh_entropy_probs);
280   } else {
281     g_print ("  %-32s : %d\n", "refresh_golden_frame",
282         frame_hdr->refresh_golden_frame);
283     g_print ("  %-32s : %d\n", "refresh_alternate_frame",
284         frame_hdr->refresh_alternate_frame);
285     if (!frame_hdr->refresh_golden_frame) {
286       g_print ("  %-32s : %d\n", "copy_buffer_to_golden",
287           frame_hdr->copy_buffer_to_golden);
288     }
289     if (!frame_hdr->refresh_alternate_frame) {
290       g_print ("  %-32s : %d\n", "copy_buffer_to_alternate",
291           frame_hdr->copy_buffer_to_alternate);
292     }
293     g_print ("  %-32s : %d\n", "sign_bias_golden", frame_hdr->sign_bias_golden);
294     g_print ("  %-32s : %d\n", "sign_bias_alternate",
295         frame_hdr->sign_bias_alternate);
296     g_print ("  %-32s : %d\n", "refresh_entropy_probs",
297         frame_hdr->refresh_entropy_probs);
298     g_print ("  %-32s : %d\n", "refresh_last", frame_hdr->refresh_last);
299   }
300 
301   g_print ("  %-32s : %d\n", "mb_no_skip_coeff", frame_hdr->mb_no_skip_coeff);
302   if (frame_hdr->mb_no_skip_coeff) {
303     g_print ("  %-32s : %d\n", "prob_skip_false", frame_hdr->prob_skip_false);
304   }
305 
306   if (!frame_hdr->key_frame) {
307     g_print ("  %-32s : %d\n", "prob_intra", frame_hdr->prob_intra);
308     g_print ("  %-32s : %d\n", "prob_last", frame_hdr->prob_last);
309     g_print ("  %-32s : %d\n", "prob_gf", frame_hdr->prob_gf);
310   }
311 
312   print_quant_indices (&frame_hdr->quant_indices);
313   print_mv_probs (&frame_hdr->mv_probs);
314   print_mode_probs (&frame_hdr->mode_probs);
315 }
316 
317 gint
main(int argc,char ** argv)318 main (int argc, char **argv)
319 {
320   FILE *fp = NULL;
321   guint8 buf[(VP8_FRAME_HDR_SIZE + 7) / 8];
322   IVFFileHdr ivf_file_hdr;
323   IVFFrameHdr ivf_frame_hdr;
324   GstVp8Parser parser;
325   GstVp8FrameHdr frame_hdr;
326   guint hdr_size, frame_num = 0;
327 
328   g_assert (sizeof (buf) >= IVF_FILE_HDR_SIZE);
329   g_assert (sizeof (buf) >= IVF_FRAME_HDR_SIZE);
330 
331   if (argc < 2) {
332     g_printerr ("Usage: %s <IVF file>\n", argv[0]);
333     return 1;
334   }
335 
336   fp = fopen (argv[1], "r");
337   if (!fp) {
338     g_printerr ("failed to open IVF file (%s)\n", argv[1]);
339     goto error;
340   }
341 
342   if (fread (buf, IVF_FILE_HDR_SIZE, 1, fp) != 1) {
343     g_printerr ("failed to read IVF header\n");
344     goto error;
345   }
346 
347   if (!parse_ivf_file_header (&ivf_file_hdr, buf, IVF_FILE_HDR_SIZE)) {
348     g_printerr ("failed to parse IVF header\n");
349     goto error;
350   }
351 
352   gst_vp8_parser_init (&parser);
353   while (fread (buf, IVF_FRAME_HDR_SIZE, 1, fp) == 1) {
354     if (!parse_ivf_frame_header (&ivf_frame_hdr, buf, IVF_FRAME_HDR_SIZE)) {
355       g_printerr ("fail to parse IVF frame header\n");
356       goto error;
357     }
358 
359     g_print ("Frame #%d @ offset %lu\n", frame_num, (gulong) ftell (fp));
360     hdr_size = MIN (sizeof (buf), ivf_frame_hdr.frame_size);
361     if (fread (buf, hdr_size, 1, fp) != 1) {
362       g_printerr ("failed to read VP8 frame header\n");
363       goto error;
364     }
365 
366     hdr_size = ivf_frame_hdr.frame_size - hdr_size;
367     if (hdr_size > 0 && fseek (fp, hdr_size, SEEK_CUR) != 0) {
368       g_printerr ("failed to skip frame data (%u bytes): %s\n",
369           ivf_frame_hdr.frame_size, strerror (errno));
370       goto error;
371     }
372 
373     memset (&frame_hdr, 0, sizeof (frame_hdr));
374     if (gst_vp8_parser_parse_frame_header (&parser, &frame_hdr, buf,
375             ivf_frame_hdr.frame_size) != GST_VP8_PARSER_OK) {
376       g_printerr ("failed to parse frame header\n");
377       goto error;
378     }
379 
380     print_frame_header (&frame_hdr);
381     print_segmentation (&parser.segmentation);
382     print_mb_lf_adjustments (&parser.mb_lf_adjust);
383     g_print ("\n");
384 
385     frame_num++;
386   }
387 
388   fclose (fp);
389   return 0;
390 
391 error:
392   if (fp)
393     fclose (fp);
394   return 1;
395 }
396