/*
* dump_state.c
* Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org>
* Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca>
*
* This file is part of mpeg2dec, a free MPEG-2 video stream decoder.
* See http://libmpeg2.sourceforge.net/ for updates.
*
* mpeg2dec is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* mpeg2dec is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "mpeg2.h"
void dump_state (FILE * f, mpeg2_state_t state, const mpeg2_info_t * info,
int offset, int verbose);
static struct {
const mpeg2_sequence_t * ptr;
mpeg2_sequence_t value;
} last_sequence;
static struct {
const mpeg2_gop_t * ptr;
mpeg2_gop_t value;
} last_gop;
static struct save_buf {
const mpeg2_fbuf_t * ptr;
mpeg2_fbuf_t value;
} last_curbuf, last_dispbuf, last_discbuf, buf_code_list[26];
static int buf_code_index = 0;
static int buf_code_new = -1;
static struct save_pic {
const mpeg2_picture_t * ptr;
mpeg2_picture_t value;
} last_curpic, last_curpic2, last_disppic, last_disppic2, pic_code_list[26];
static int pic_code_index = 0;
static int pic_code_new = -1;
static int sequence_match (const mpeg2_sequence_t * seq)
{
return (last_sequence.ptr == seq &&
(seq == NULL ||
!memcmp (seq, &last_sequence.value, sizeof (mpeg2_sequence_t))));
}
static void sequence_save (const mpeg2_sequence_t * seq)
{
last_sequence.ptr = seq;
if (seq != NULL)
last_sequence.value = *seq;
}
static char seq_code (const mpeg2_sequence_t * seq)
{
if (seq == NULL)
return '-';
else if (sequence_match (seq))
return 'S';
else
return '?';
}
static int gop_match (const mpeg2_gop_t * gop)
{
return (last_gop.ptr == gop &&
(gop == NULL ||
!memcmp (gop, &last_gop.value, sizeof (mpeg2_gop_t))));
}
static void gop_save (const mpeg2_gop_t * gop)
{
last_gop.ptr = gop;
if (gop != NULL)
last_gop.value = *gop;
}
static char gop_code (const mpeg2_gop_t * gop)
{
if (gop == NULL)
return '-';
else if (gop_match (gop))
return 'G';
else
return '?';
}
static int fbuf_match (const mpeg2_fbuf_t * fbuf, struct save_buf * saved)
{
return (saved->ptr == fbuf &&
(fbuf == NULL ||
!memcmp (fbuf, &saved->value, sizeof (mpeg2_fbuf_t))));
}
static void fbuf_save (const mpeg2_fbuf_t * fbuf, struct save_buf * saved)
{
saved->ptr = fbuf;
if (fbuf != NULL)
saved->value = *fbuf;
}
static char buf_code (const mpeg2_fbuf_t * fbuf)
{
int i;
if (fbuf == NULL)
return '-';
for (i = 0; i < 26; i++)
if (fbuf_match (fbuf, buf_code_list + i))
return ((i == buf_code_new) ? 'A' : 'a') + i;
return '?';
}
static void buf_code_add (const mpeg2_fbuf_t * fbuf, FILE * f)
{
int i;
if (fbuf == NULL)
fprintf (f, "buf_code_add error\n");
for (i = 0; i < 26; i++)
if (buf_code_list[i].ptr == fbuf)
fprintf (f, "buf_code_add error\n");
buf_code_new = buf_code_index;
fbuf_save (fbuf, buf_code_list + buf_code_index);
if (++buf_code_index == 26)
buf_code_index = 0;
}
static void buf_code_del (const mpeg2_fbuf_t * fbuf)
{
int i;
if (fbuf == NULL)
return;
for (i = 0; i < 26; i++)
if (fbuf_match (fbuf, buf_code_list + i)) {
buf_code_list[i].ptr = NULL;
return;
}
}
static int picture_match (const mpeg2_picture_t * pic, struct save_pic * saved)
{
return (saved->ptr == pic &&
(pic == NULL ||
!memcmp (pic, &saved->value, sizeof (mpeg2_picture_t))));
}
static void picture_save (const mpeg2_picture_t * pic, struct save_pic * saved)
{
saved->ptr = pic;
if (pic != NULL)
saved->value = *pic;
}
static char pic_code (const mpeg2_picture_t * pic)
{
int i;
if (pic == NULL)
return '-';
for (i = 0; i < 26; i++)
if (picture_match (pic, pic_code_list + i))
return ((i == pic_code_new) ? 'A' : 'a') + i;
return '?';
}
static void pic_code_add (const mpeg2_picture_t * pic, FILE * f)
{
int i;
if (pic == NULL)
fprintf (f, "pic_code_add error\n");
for (i = 0; i < 26; i++)
if (pic_code_list[i].ptr == pic)
fprintf (f, "pic_code_add error\n");
pic_code_new = pic_code_index;
picture_save (pic, pic_code_list + pic_code_index);
if (++pic_code_index == 26)
pic_code_index = 0;
}
static void pic_code_del (const mpeg2_picture_t * pic)
{
int i;
if (pic == NULL)
return;
for (i = 0; i < 26; i++)
if (picture_match (pic, pic_code_list + i)) {
pic_code_list[i].ptr = NULL;
return;
}
}
void dump_state (FILE * f, mpeg2_state_t state, const mpeg2_info_t * info,
int offset, int verbose)
{
static const char * state_name[] = {
"BUFFER", "SEQUENCE", "SEQUENCE_REPEATED","GOP",
"PICTURE", "SLICE_1ST", "PICTURE_2ND", "SLICE", "END",
"INVALID", "INVALID_END", "SEQUENCE_MODIFIED"
};
static const char * profile[] = { "HP", "Spatial", "SNR", "MP", "SP" };
static const char * level[] = { "HL", "H-14", "ML", "LL" };
static const char * profile2[] = { "422@HL", NULL, NULL, "422@ML",
NULL, NULL, NULL, NULL, "MV@HL",
"MV@H-14", NULL, "MV@ML", "MV@LL" };
static const char * video_fmt[] = { "COMPONENT", "PAL", "NTSC", "SECAM", "MAC"};
static const char coding_type[] = { '0', 'I', 'P', 'B', 'D', '5', '6', '7'};
static const char * colour[] = { NULL, "BT.709", "UNSPECIFIED", NULL,
"BT.470-2/M", "BT.470-2/B,G",
"SMPTE170M", "SMPTE240M", "LINEAR" };
static const char * colour3[] = { NULL, "BT.709", "UNSPEC_COLORS", NULL, NULL,
"BT.470-2/B,G", "SMPTE170M", "SMPTE240M" };
const mpeg2_sequence_t * seq = info->sequence;
const mpeg2_gop_t * gop = info->gop;
const mpeg2_picture_t * pic;
unsigned int i, nb_pos, pixel_width, pixel_height;
if (state == STATE_BUFFER &&
sequence_match (seq) && gop_match (gop) &&
info->user_data == NULL && info->user_data_len == 0 &&
fbuf_match (info->current_fbuf, &last_curbuf) &&
fbuf_match (info->display_fbuf, &last_dispbuf) &&
fbuf_match (info->discard_fbuf, &last_discbuf) &&
picture_match (info->current_picture, &last_curpic) &&
picture_match (info->current_picture_2nd, &last_curpic2) &&
picture_match (info->display_picture, &last_disppic) &&
picture_match (info->display_picture_2nd, &last_disppic2))
return;
fprintf (f, "%8x", offset);
if (verbose > 1) {
switch (state) {
case STATE_PICTURE:
buf_code_add (info->current_fbuf, f);
pic_code_add (info->current_picture, f);
break;
case STATE_PICTURE_2ND:
pic_code_add (info->current_picture_2nd, f);
break;
case STATE_SEQUENCE_MODIFIED:
if (last_sequence.value.width != seq->width ||
last_sequence.value.height != seq->height ||
last_sequence.value.chroma_width != seq->chroma_width ||
last_sequence.value.chroma_height != seq->chroma_height ||
((last_sequence.value.flags & SEQ_FLAG_LOW_DELAY) !=
(seq->flags & SEQ_FLAG_LOW_DELAY)))
fprintf (f, " (INVALID)");
case STATE_SEQUENCE:
sequence_save (seq);
break;
break;
case STATE_GOP:
gop_save (gop);
break;
default:
break;
}
fprintf (f, " %c%c %c%c%c %c%c%c %c", seq_code (seq), gop_code (gop),
buf_code (info->current_fbuf),
pic_code (info->current_picture),
pic_code (info->current_picture_2nd),
buf_code (info->display_fbuf),
pic_code (info->display_picture),
pic_code (info->display_picture_2nd),
buf_code (info->discard_fbuf));
if (state == STATE_SLICE || state == STATE_END ||
state == STATE_INVALID_END) {
if (state != STATE_SLICE)
buf_code_del (info->display_fbuf);
buf_code_del (info->discard_fbuf);
pic_code_del (info->display_picture);
pic_code_del (info->display_picture_2nd);
}
buf_code_new = pic_code_new = -1;
}
fprintf (f, " %s", state_name[state]);
switch (state) {
case STATE_SEQUENCE:
case STATE_SEQUENCE_REPEATED:
case STATE_SEQUENCE_MODIFIED:
if (seq->flags & SEQ_FLAG_MPEG2)
fprintf (f, " MPEG2");
if (0x10 <= seq->profile_level_id && seq->profile_level_id < 0x60 &&
!(seq->profile_level_id & 1) &&
4 <= (seq->profile_level_id & 15) &&
(seq->profile_level_id & 15) <= 10)
fprintf (f, " %s@%s",
profile[(seq->profile_level_id >> 4) - 1],
level[((seq->profile_level_id & 15) - 4) >> 1]);
else if (0x82 <= seq->profile_level_id &&
seq->profile_level_id<= 0x8e &&
profile2[seq->profile_level_id - 0x82])
fprintf (f, " %s", profile2[seq->profile_level_id - 0x82]);
else if (seq->flags & SEQ_FLAG_MPEG2)
fprintf (f, " profile %02x", seq->profile_level_id);
if (seq->flags & SEQ_FLAG_CONSTRAINED_PARAMETERS)
fprintf (f, " CONST");
if (seq->flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE)
fprintf (f, " PROG");
if (seq->flags & SEQ_FLAG_LOW_DELAY)
fprintf (f, " LOWDELAY");
if ((seq->flags & SEQ_MASK_VIDEO_FORMAT) <
SEQ_VIDEO_FORMAT_UNSPECIFIED)
fprintf (f, " %s", video_fmt[(seq->flags & SEQ_MASK_VIDEO_FORMAT) /
SEQ_VIDEO_FORMAT_PAL]);
if (seq->flags & SEQ_FLAG_COLOUR_DESCRIPTION) {
if (seq->colour_primaries == seq->transfer_characteristics &&
seq->colour_primaries == seq->matrix_coefficients &&
seq->colour_primaries <= 7 && colour3[seq->colour_primaries])
fprintf (f, " %s", colour3[seq->colour_primaries]);
else {
char prim[16], trans[16], matrix[16];
sprintf (prim, "%d", seq->colour_primaries);
sprintf (trans, "%d", seq->transfer_characteristics);
sprintf (matrix, "%d", seq->matrix_coefficients);
if (seq->colour_primaries <= 7 &&
colour[seq->colour_primaries])
strncpy (prim, colour[seq->colour_primaries], 15);
if (seq->transfer_characteristics <= 8 &&
colour[seq->transfer_characteristics])
strncpy (trans, colour[seq->transfer_characteristics], 15);
if (seq->matrix_coefficients == 4)
strncpy (matrix, "FCC", 15);
else if (seq->matrix_coefficients <= 7 &&
colour[seq->matrix_coefficients])
strncpy (matrix, colour[seq->matrix_coefficients], 15);
fprintf (f, " COLORS (prim %s trans %s matrix %s)",
prim, trans, matrix);
}
}
fprintf (f, " %dx%d chroma %dx%d fps %.*f maxBps %d vbv %d "
"picture %dx%d display %dx%d pixel %dx%d",
seq->width, seq->height,
seq->chroma_width, seq->chroma_height,
27000000%seq->frame_period?2:0, 27000000.0/seq->frame_period,
seq->byte_rate, seq->vbv_buffer_size,
seq->picture_width, seq->picture_height,
seq->display_width, seq->display_height,
seq->pixel_width, seq->pixel_height);
if (mpeg2_guess_aspect (seq, &pixel_width, &pixel_height))
fprintf (f, " guessed %dx%d", pixel_width, pixel_height);
fprintf (f, "\n");
break;
case STATE_GOP:
if (gop->flags & GOP_FLAG_DROP_FRAME)
fprintf (f, " DROP");
if (gop->flags & GOP_FLAG_CLOSED_GOP)
fprintf (f, " CLOSED");
if (gop->flags & GOP_FLAG_BROKEN_LINK)
fprintf (f, " BROKEN");
fprintf (f, " %2d:%2d:%2d:%2d\n",
gop->hours, gop->minutes, gop->seconds, gop->pictures);
break;
case STATE_PICTURE:
case STATE_PICTURE_2ND:
pic = ((state == STATE_PICTURE) ?
info->current_picture : info->current_picture_2nd);
fprintf (f, " %c",
coding_type[pic->flags & PIC_MASK_CODING_TYPE]);
if (pic->flags & PIC_FLAG_PROGRESSIVE_FRAME)
fprintf (f, " PROG");
if (pic->flags & PIC_FLAG_SKIP)
fprintf (f, " SKIP");
fprintf (f, " fields %d", pic->nb_fields);
if (pic->flags & PIC_FLAG_TOP_FIELD_FIRST)
fprintf (f, " TFF");
if (pic->flags & PIC_FLAG_TAGS)
fprintf (f, " pts %08x dts %08x", pic->tag, pic->tag2);
fprintf (f, " time_ref %d", pic->temporal_reference);
if (pic->flags & PIC_FLAG_COMPOSITE_DISPLAY)
fprintf (f, " composite %05x", pic->flags >> 12);
fprintf (f, " offset");
nb_pos = pic->nb_fields;
if (seq->flags & SEQ_FLAG_PROGRESSIVE_SEQUENCE)
nb_pos >>= 1;
for (i = 0; i < nb_pos; i++)
fprintf (f, " %d/%d",
pic->display_offset[i].x, pic->display_offset[i].y);
fprintf (f, "\n");
break;
default:
fprintf (f, "\n");
}
if (verbose > 2 && info->user_data_len) {
fprintf (f, " USER_DATA %d bytes\n", info->user_data_len);
if (verbose > 3)
for (i = 0; i < info->user_data_len; i += 16) {
unsigned int j;
fprintf (f, " ");
for (j = i; j < i + 16; j++)
if (j < info->user_data_len)
fprintf (f, "%02x ", info->user_data[j]);
else
fprintf (f, " ");
fprintf (f, " ");
for (j = i; j < i + 16; j++)
if (j < info->user_data_len &&
32 <= info->user_data[j] && info->user_data[j] <= 126)
fprintf (f, "%c", info->user_data[j]);
else
fprintf (f, " ");
fprintf (f, "\n");
}
}
if (state == STATE_END || state == STATE_INVALID_END) {
sequence_save (NULL);
gop_save (NULL);
fbuf_save (NULL, &last_curbuf);
fbuf_save (NULL, &last_dispbuf);
fbuf_save (NULL, &last_discbuf);
picture_save (NULL, &last_curpic);
picture_save (NULL, &last_curpic2);
picture_save (NULL, &last_disppic);
picture_save (NULL, &last_disppic2);
} else {
sequence_save (seq);
gop_save (gop);
fbuf_save (info->current_fbuf, &last_curbuf);
fbuf_save (info->display_fbuf, &last_dispbuf);
fbuf_save (info->discard_fbuf, &last_discbuf);
picture_save (info->current_picture, &last_curpic);
picture_save (info->current_picture_2nd, &last_curpic2);
picture_save (info->display_picture, &last_disppic);
picture_save (info->display_picture_2nd, &last_disppic2);
}
}