--- /dev/null
+#include "../libzmpeg3.h"
+
+/* zig-zag scan */
+uint8_t zvideo_t::
+zig_zag_scan_nommx[64] = {
+ 0 , 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
+};
+
+/* alternate scan */
+uint8_t zvideo_t::
+alternate_scan_nommx[64] = {
+ 0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49,
+ 41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43,
+ 51, 59, 20, 28, 5, 13, 6, 14, 21, 29, 36, 44, 52, 60, 37, 45,
+ 53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63,
+};
+
+/* default intra quantization matrix */
+uint8_t zvideo_t::
+default_intra_quantizer_matrix[64] = {
+ 8, 16, 19, 22, 26, 27, 29, 34,
+ 16, 16, 22, 24, 27, 29, 34, 37,
+ 19, 22, 26, 27, 29, 34, 34, 38,
+ 22, 22, 26, 27, 29, 34, 37, 40,
+ 22, 26, 27, 29, 32, 35, 40, 48,
+ 26, 27, 29, 32, 35, 40, 48, 58,
+ 26, 27, 29, 34, 38, 46, 56, 69,
+ 27, 29, 35, 38, 46, 56, 69, 83,
+};
+
+double zvideo_t::
+frame_rate_table[16] = {
+ 0.0, /* Pad */
+ (double)24000.0/1001.0, /* Official frame rates */
+ (double)24.0,
+ (double)25.0,
+ (double)30000.0/1001.0,
+ (double)30.0,
+ (double)50.0,
+ (double)60000.0/1001.0,
+ (double)60.0,
+
+ 1.0, 5.0, 10.0, 12.0, 15.0, /* Unofficial economy rates */
+ 0.0, 0.0,
+};
+
+static int blk_cnt_tab[3] = { 6, 8, 12 };
+
+int zvideo_t::
+init_decoder()
+{
+ int i, j, sz, cc;
+ long size[4], padding[2]; /* Size of Y, U, and V buffers */
+
+ if( !mpeg2 ) { /* force MPEG-1 parameters */
+ prog_seq = 1;
+ prog_frame = 1;
+ pict_struct = pics_FRAME_PICTURE;
+ frame_pred_dct = 1;
+ chroma_format = cfmt_420;
+ matrix_coefficients = 5;
+ }
+
+/* Get dimensions rounded to nearest multiple of coded macroblocks */
+ mb_width = (horizontal_size + 15) / 16;
+ mb_height = (mpeg2 && !prog_seq) ?
+ (2 * ((vertical_size + 31) / 32)) : ((vertical_size + 15) / 16);
+ coded_picture_width = 16 * mb_width;
+ coded_picture_height = 16 * mb_height;
+ chrom_width = (chroma_format == cfmt_444) ?
+ coded_picture_width : (coded_picture_width >> 1);
+ chrom_height = (chroma_format != cfmt_420) ?
+ coded_picture_height : (coded_picture_height >> 1);
+ blk_cnt = blk_cnt_tab[chroma_format - 1];
+
+/* Get sizes of YUV buffers */
+ padding[0] = 16*coded_picture_width + 16;
+ size[0] = coded_picture_width*coded_picture_height + padding[0];
+
+ padding[1] = 16*chrom_width + 16;
+ size[1] = chrom_width*chrom_height + padding[1];
+ size[3] = (size[2] = (llw * llh)) / 4;
+
+/* Allocate contiguous fragments for YUV buffers for hardware YUV decoding */
+ sz = size[0] + 2*size[1];
+ yuv_buffer[0] = new uint8_t[sz]; memset(yuv_buffer[0],0,sz);
+ yuv_buffer[1] = new uint8_t[sz]; memset(yuv_buffer[1],0,sz);
+ yuv_buffer[2] = new uint8_t[sz]; memset(yuv_buffer[2],0,sz);
+
+ if( scalable_mode == slice_decoder_t::sc_SPAT ) {
+ sz = size[2] + 2 * size[3];
+ yuv_buffer[3] = new uint8_t[sz]; memset(yuv_buffer[3],0,sz);
+ yuv_buffer[4] = new uint8_t[sz]; memset(yuv_buffer[4],0,sz);
+ }
+
+ tdat = new uint8_t[4 * mb_width * mb_height];
+ memset(tdat, 0, 4 * mb_width * mb_height);
+
+ slice_decoder_t::init_tables();
+
+/* Direct pointers to areas of contiguous fragments in YVU order per Microsoft */
+ for( cc=0; cc<3; ++cc ) {
+ llframe0[cc] = 0;
+ llframe1[cc] = 0;
+ newframe[cc] = 0;
+ }
+
+ refframe[0] = yuv_buffer[0];
+ oldrefframe[0] = yuv_buffer[1];
+ auxframe[0] = yuv_buffer[2];
+ sz = size[0];
+ refframe[2] = yuv_buffer[0] + sz;
+ oldrefframe[2] = yuv_buffer[1] + sz;
+ auxframe[2] = yuv_buffer[2] + sz;
+ sz += size[1];
+ refframe[1] = yuv_buffer[0] + sz;
+ oldrefframe[1] = yuv_buffer[1] + sz;
+ auxframe[1] = yuv_buffer[2] + sz;
+
+ if( scalable_mode == slice_decoder_t::sc_SPAT ) {
+/* this assumes lower layer is 4:2:0 */
+ sz = padding[0];
+ llframe0[0] = yuv_buffer[3] + sz;
+ llframe1[0] = yuv_buffer[4] + sz;
+ sz = padding[1] + size[2];
+ llframe0[2] = yuv_buffer[3] + sz;
+ llframe1[2] = yuv_buffer[4] + sz;
+ sz += size[3];
+ llframe0[1] = yuv_buffer[3] + sz;
+ llframe1[1] = yuv_buffer[4] + sz;
+ }
+
+/* Initialize the YUV tables for software YUV decoding */
+ cr_to_r = new int[256];
+ crb_to_g = new int[256*256];
+ cb_to_b = new int[256];
+ int *cr_to_r_ptr = cr_to_r + 128;
+ int *crb_to_g_ptr = crb_to_g + 128*256 + 128;
+ int *cb_to_b_ptr = cb_to_b + 128;
+
+ for( i=-128; i<128; ++i ) {
+ cr_to_r_ptr[i] = (int)(1.371*i * 65536.);
+ for( j=-128; j<128; ++j )
+ crb_to_g_ptr[i*256 + j] = (int)((-0.698*i + -0.336*j) * 65536.);
+ cb_to_b_ptr[i] = (int)((1.732*i) * 65536.);
+ }
+
+ decoder_initted = 1;
+ return 0;
+}
+
+int zvideo_t::
+delete_decoder()
+{
+ if( yuv_buffer[0] ) delete [] yuv_buffer[0];
+ if( yuv_buffer[1] ) delete [] yuv_buffer[1];
+ if( yuv_buffer[2] ) delete [] yuv_buffer[2];
+
+ if( subtitle_frame[0] ) delete [] subtitle_frame[0];
+ if( subtitle_frame[1] ) delete [] subtitle_frame[1];
+ if( subtitle_frame[2] ) delete [] subtitle_frame[2];
+
+ if( llframe0[0] ) {
+ delete [] yuv_buffer[3];
+ delete [] yuv_buffer[4];
+ }
+ delete [] tdat;
+
+ delete [] cr_to_r;
+ delete [] crb_to_g;
+ delete [] cb_to_b;
+ return 0;
+}
+
+void zvideo_t::
+init_scantables()
+{
+ zigzag_scan_table = zig_zag_scan_nommx;
+ alternate_scan_table = alternate_scan_nommx;
+}
+
+void zvideo_t::
+init_video()
+{
+ int result;
+ init_decoder();
+ track->width = horizontal_size;
+ track->height = vertical_size;
+ track->frame_rate = frame_rate;
+ demuxer_t *demux = vstream->demuxer;
+
+ /* Try to get the length of the file from GOP's */
+ if( !track->frame_offsets ) {
+ if( src->is_video_stream() ) {
+ /* Load the first GOP */
+ rewind_video(0);
+ result = vstream->next_code(GOP_START_CODE);
+ if( !result ) vstream->get_bits(32);
+ if( !result ) result = get_gop_header();
+ first_frame = gop_to_frame(&gop_timecode);
+ /* GOPs are supposed to have 16 frames */
+ frames_per_gop = 16;
+ /* Read the last GOP in the file by seeking backward. */
+ demux->seek_byte(demux->movie_size());
+ demux->start_reverse();
+ result = demux->prev_code(GOP_START_CODE);
+ demux->start_forward();
+ vstream->reset();
+ vstream->get_bits(8);
+ if(!result) result = get_gop_header();
+ last_frame = gop_to_frame(&gop_timecode);
+//zmsgs("3 %p\n", this);
+ /* Count number of frames to end */
+ while( !result ) {
+ result = vstream->next_code(PICTURE_START_CODE);
+ if( !result ) {
+ vstream->get_byte_noptr();
+ ++last_frame;
+ }
+ }
+
+ track->total_frames = last_frame-first_frame+1;
+//zmsgs("mpeg3video_new 3 %ld\n", track->total_frames);
+ }
+ else {
+ /* Try to get the length of the file from the multiplexing. */
+ /* Need a table of contents */
+/* first_frame = 0;
+ * track->total_frames = last_frame =
+ * (long)(demux->length() * frame_rate);
+ * first_frame = 0;
+ */
+ }
+ }
+ else {
+ /* Get length from table of contents */
+ track->total_frames = track->total_frame_offsets-1;
+ }
+
+ maxframe = track->total_frames;
+ rewind_video(0);
+}
+
+int zvideo_t::
+video_pts_padding()
+{
+ int result = 0;
+ if( track->video_time >= 0 && src->pts_padding > 0 ) {
+ int pts_framenum = track->video_time*track->frame_rate + 0.5;
+ int padding = pts_framenum - track->pts_position;
+ if( padding > 0 ) {
+ if( track->vskip <= 0 ) {
+ int limit = 3;
+ if( padding > limit ) {
+ zmsgs("video start padding pid %02x @ %12d (%12.6f) %d\n",
+ track->pid, framenum, track->get_video_time(), padding);
+ track->vskip = 1;
+ result = 1;
+ }
+ }
+ else if( !(++track->vskip & 1) || padding > track->frame_rate )
+ result = 1;
+ if( result ) ++track->pts_position;
+ }
+ else if( track->vskip > 0 ) {
+ zmsgs("video end padding pid %02x @ %12d (%12.6f) %d\n",
+ track->pid, framenum, track->get_video_time(), (1+track->vskip)/2);
+ track->vskip = 0;
+ }
+ }
+ return result;
+}
+
+int zvideo_t::
+video_pts_skipping()
+{
+ int result = 0;
+ if( track->video_time >= 0 && src->pts_padding > 0 ) {
+ int pts_framenum = track->video_time*track->frame_rate + 0.5;
+ int skipping = track->pts_position - pts_framenum;
+ if( skipping > 0 ) {
+ if( track->vskip >= 0 ) {
+ int limit = 3;
+ if( skipping > limit ) {
+ zmsgs("video start skipping pid %02x @ %12d (%12.6f) %d frames\n",
+ track->pid, framenum, track->get_video_time(), skipping);
+ track->vskip = -1;
+ result = 1;
+ }
+ }
+ else if( !(--track->vskip & 1) || skipping > track->frame_rate )
+ result = 1;
+ if( result ) --track->pts_position;
+ }
+ else if( track->vskip < 0 ) {
+ zmsgs("video end skipping pid %02x @ %12d (%12.6f) %d frames\n",
+ track->pid, framenum, track->get_video_time(), (1-track->vskip)/2);
+ track->vskip = 0;
+ }
+ }
+ return result;
+}
+
+int zvideo_t::
+eof()
+{
+ while( vstream->eof() ) {
+ demuxer_t *demux = vstream->demuxer;
+ if( demux->seek_phys() ) return 1;
+ }
+ return 0;
+}
+
+
+/* The way they do field based encoding, */
+/* the I frames have the top field but both the I frame and */
+/* subsequent P frame are interlaced to make the keyframe. */
+
+int zvideo_t::
+read_picture()
+{
+ int result = 0;
+ int field = 0;
+ got_top = got_bottom = 0;
+ secondfield = 0;
+
+ do {
+ if( (result=eof()) != 0 ) break;
+ if( (result=get_header()) != 0 ) break;
+ if( pict_struct != pics_FRAME_PICTURE ) secondfield = field;
+ /* if dropping frames then skip B frames, */
+ /* Don't skip the B frames which generate original */
+ /* repeated frames at the end of the skip sequence */
+ if( !skip_bframes || pict_type != pic_type_B ||
+ repeat_fields > 2*skip_bframes ) {
+ if( (result=get_picture()) != 0 ) break;
+ }
+ ++field;
+ if( pict_struct == pics_FRAME_PICTURE ) { got_top = got_bottom = field; break; }
+ if( pict_struct == pics_TOP_FIELD ) got_top = field;
+ else if( pict_struct == pics_BOTTOM_FIELD ) got_bottom = field;
+ } while( !secondfield );
+
+ if( pict_type != pic_type_B )
+ ++ref_frames;
+
+ return result;
+}
+
+int zvideo_t::
+read_frame_backend(int zskip_bframes)
+{
+ int result = 0;
+//if( src->seekable ) {
+// int app_pos = track->apparent_position();
+// double vtime = track->get_video_time();
+// int pts_frm = vtime * track->frame_rate + 0.5;
+// zmsgs(" apr_pos %f: %d/%d + %d: pts_frame %d + %d\n", vtime,
+// app_pos, framenum, app_pos - framenum, pts_frm, pts_frm-framenum);
+//}
+ if( !mpeg2 ) current_field = repeat_fields = 0;
+
+ /* Repeat if current_field is more than 1 field from repeat_fields */
+ if( !repeat_fields || current_field+2 >= repeat_fields ) {
+ if( (repeat_fields -= current_field) < 0 ) repeat_fields = 0;
+ track->update_video_time();
+
+ // if pts lags framenum, skip to next picture
+ // only skip once (double speed) to catch up
+ while( !(result=find_header()) ) {
+ if( !video_pts_skipping() ) break;
+ vstream->refill();
+ }
+
+ // if framenum lags pts, repeat picture
+ if( !result && !video_pts_padding() ) {
+ track->update_frame_pts();
+ skip_bframes = zskip_bframes;
+//static const char *pstruct[] = { "nil", "top", "bot", "fld" };
+//zmsgs("video %d PID %02x frame %d vtime %12.5f %c/%s %d 0x%010lx/0x%010lx %d/%d\n",
+// result, track->pid, framenum, track->get_video_time(), "XIPBD"[pict_type],
+// pstruct[pict_struct], skip_bframes, vstream->demuxer->last_packet_start,
+// vstream->demuxer->absolute_position()-vstream->demuxer->zdata.length(),
+// repeat_fields, current_field);
+ result = read_picture();
+#if 0
+{ char fn[512];
+ snprintf(&fn[0],sizeof(fn),"/tmp/dat/f%05d.pnm",framenum);
+ int fd = open(&fn[0],O_CREAT+O_TRUNC+O_WRONLY,0666);
+ write(fd,&fn, snprintf(&fn[0],sizeof(fn),
+ "P5\n%d %d\n255\n", coded_picture_width, coded_picture_height));
+ write(fd,output_src[0],coded_picture_width*coded_picture_height);
+ close(fd);
+}
+#endif
+ }
+ }
+
+ if( !result ) {
+ if( mpeg2 ) current_field = !repeat_fields ? 0 : current_field+2;
+ decode_subtitle();
+ last_number = framenum++;
+ }
+
+ return result;
+}
+
+int* zvideo_t::
+get_scaletable(int in_l, int out_l)
+{
+ int *result = new int[out_l];
+ double scale = (double)in_l / out_l;
+ for( int i=0; i<out_l; ++i ) {
+ result[i] = (int)(scale * i);
+ }
+ return result;
+}
+
+long zvideo_t::
+gop_to_frame(timecode_t *gop_timecode)
+{
+/* Mirror of what mpeg2enc does */
+ int fps = (int)(frame_rate + 0.5);
+ int hour = gop_timecode->hour;
+ int minute = gop_timecode->minute;
+ int second = gop_timecode->second;
+ int frame = gop_timecode->frame;
+ long result = ((long)hour*3600 + minute*60 + second)*fps + frame;
+ return result;
+}
+
+
+/* ======================================================================= */
+/* ENTRY POINTS */
+/* ======================================================================= */
+
+
+
+zvideo_t::
+video_t(zmpeg3_t *zsrc, zvtrack_t *ztrack)
+{
+ src = zsrc;
+ track = ztrack;
+ vstream = new bits_t(zsrc, track->demuxer);
+//zmsgs("%d\n", vstream->eof());
+ last_number = -1;
+/* First frame is all green */
+ framenum = -1;
+ byte_seek = -1;
+ frame_seek = -1;
+ subtitle_track = -1;
+
+ init_scantables();
+ init_output();
+ allocate_slice_buffers();
+ slice_wait.lock();
+}
+
+zvideo_t *zmpeg3_t::
+new_video_t(zvtrack_t *ztrack)
+{
+ int result = 0;
+ video_t *new_video = new video_t(this,ztrack);
+
+/* Get encoding parameters from stream */
+ if( seekable ) {
+ result = new_video->get_header();
+ if( !result )
+ new_video->init_video();
+ else {
+/* No header found */
+#ifdef TODO
+ zerr("no header found.\n");
+ delete new_video;
+ new_video = 0;
+#endif
+ }
+ }
+
+ return new_video;
+}
+
+zvideo_t::
+~video_t()
+{
+ delete_slice_buffers();
+ if( decoder_initted )
+ delete_decoder();
+ delete vstream;
+ delete cc;
+ if( x_table ) {
+ delete [] x_table;
+ delete [] y_table;
+ }
+}
+
+int zvideo_t::
+set_cpus(int cpus)
+{
+ return 0;
+}
+
+int zvideo_t::
+set_mmx(int use_mmx)
+{
+ init_scantables();
+ return 0;
+}
+
+/* Read all the way up to and including the next picture start code */
+int zvideo_t::
+read_raw(uint8_t *output, long *size, long max_size)
+{
+ uint32_t zcode = 0;
+ long sz = 0;
+ while( zcode!=PICTURE_START_CODE && zcode!=SEQUENCE_END_CODE &&
+ sz < max_size && !eof() ) {
+ uint8_t byte = vstream->get_byte_noptr();
+ *output++ = byte;
+ zcode = (zcode << 8) | byte;
+ ++sz;
+ }
+ *size = sz;
+ return eof();
+}
+
+int zvideo_t::read_frame( uint8_t **output_rows,
+ int in_x, int in_y, int in_w, int in_h,
+ int out_w, int out_h, int color_model)
+{
+ uint8_t *y, *u, *v;
+ int frame_number, result;
+ result = 0;
+ want_yvu = 0;
+ this->output_rows = output_rows;
+ this->color_model = color_model;
+
+/* Get scaling tables */
+ if( this->out_w != out_w || this->out_h != out_h ||
+ this->in_w != in_w || this->in_h != in_h ||
+ this->in_x != in_x || this->in_y != in_y) {
+ if(x_table) {
+ delete [] x_table; x_table = 0;
+ delete [] y_table; y_table = 0;
+ }
+ }
+
+ this->out_w = out_w; this->out_h = out_h;
+ this->in_w = in_w; this->in_h = in_h;
+ this->in_x = in_x; this->in_y = in_y;
+
+ if( !x_table ) {
+ x_table = get_scaletable(in_w, out_w);
+ y_table = get_scaletable(in_h, out_h);
+ }
+//zmsgs("mpeg3video_read_frame 1 %d\n", framenum);
+
+/* Recover from cache */
+ frame_number = frame_seek >= 0 ? frame_seek : framenum;
+ cache_t *cache = track->frame_cache;
+ if( frame_seek != last_number &&
+ cache->get_frame(frame_number, &y, &u, &v) ) {
+//zmsgs("1 %d\n", frame_number);
+ /* Transfer with cropping */
+ if( y ) present_frame(y, u, v);
+ /* Advance either framenum or frame_seek */
+ if( frame_number == framenum )
+ framenum = ++frame_number;
+ else if( frame_number == frame_seek )
+ frame_seek = ++frame_number;
+ }
+ else {
+ /* Only decode if it's a different frame */
+ if( frame_seek < 0 || last_number < 0 ||
+ frame_seek != last_number) {
+ if( !result ) result = seek();
+ if( !result ) result = read_frame_backend(0);
+ }
+ else {
+ framenum = frame_seek + 1;
+ last_number = frame_seek;
+ frame_seek = -1;
+ }
+ if( output_src[0] )
+ present_frame(output_src[0], output_src[1], output_src[2]);
+ }
+ return result;
+}
+
+int zvideo_t::
+read_yuvframe(char *y_output, char *u_output, char *v_output,
+ int in_x, int in_y, int in_w, int in_h)
+{
+ uint8_t *y = 0, *u = 0, *v = 0;
+ int result = 0;
+//zmsgs("1 %d\n", framenum);
+ want_yvu = 1;
+ this->y_output = y_output;
+ this->u_output = u_output;
+ this->v_output = v_output;
+ this->in_x = in_x;
+ this->in_y = in_y;
+ this->in_w = in_w;
+ this->in_h = in_h;
+
+ /* Recover from cache if framenum exists */
+ int frame_number = frame_seek >= 0 ? frame_seek : framenum;
+ cache_t *cache = track->frame_cache;
+ if( cache->get_frame(frame_number, &y, &u, &v) ) {
+//zmsgs("1 %d\n", frame_number);
+ /* Transfer with cropping */
+ if( y ) present_frame(y, u, v);
+ /* Advance either framenum or frame_seek */
+ if( frame_number == framenum )
+ framenum = ++frame_number;
+ else if( frame_number == frame_seek )
+ frame_seek = ++frame_number;
+ }
+ else {
+ if( !result ) result = seek();
+ if( !result ) result = read_frame_backend(0);
+ if( !result && output_src[0] )
+ present_frame(output_src[0], output_src[1], output_src[2]);
+ }
+
+ want_yvu = 0;
+ byte_seek = -1;
+ return result;
+}
+
+int zvideo_t::
+read_yuvframe_ptr(char **y_output, char **u_output, char **v_output)
+{
+ uint8_t *y, *u, *v;
+ int frame_number, result;
+ int debug = 0;
+ result = 0;
+ want_yvu = 1;
+ *y_output = *u_output = *v_output = 0;
+
+ frame_number = frame_seek >= 0 ? frame_seek : framenum;
+ cache_t *cache = track->frame_cache;
+ if( debug ) zmsgs("%d\n", __LINE__);
+ if( cache->get_frame(frame_number, &y, &u, &v) ) {
+ if( debug ) zmsgs("%d\n", __LINE__);
+ *y_output = (char*)y;
+ *u_output = (char*)u;
+ *v_output = (char*)v;
+ /* Advance either framenum or frame_seek */
+ if( frame_number == framenum )
+ framenum = ++frame_number;
+ else if( frame_number == frame_seek )
+ frame_seek = ++frame_number;
+ if( debug ) zmsgs("%d\n", __LINE__);
+ }
+ /* Only decode if it's a different frame */
+ else if( frame_seek < 0 || last_number < 0 ||
+ frame_seek != last_number) {
+ if( debug ) zmsgs("%d\n", __LINE__);
+ if( !result ) result = seek();
+ if( debug ) zmsgs("%d\n", __LINE__);
+ if( !result ) result = read_frame_backend(0);
+ if( debug ) zmsgs("%d\n", __LINE__);
+
+ if( output_src[0] ) {
+ *y_output = (char*)output_src[0];
+ *u_output = (char*)output_src[1];
+ *v_output = (char*)output_src[2];
+ }
+ if( debug ) zmsgs("%d\n", __LINE__);
+ }
+ else {
+ if( debug ) zmsgs("%d\n", __LINE__);
+ framenum = frame_seek + 1;
+ last_number = frame_seek;
+ frame_seek = -1;
+
+ if( output_src[0 ]) {
+ *y_output = (char*)output_src[0];
+ *u_output = (char*)output_src[1];
+ *v_output = (char*)output_src[2];
+ }
+ if( debug ) zmsgs("%d\n", __LINE__);
+ }
+
+ if( debug ) zmsgs("%d\n", __LINE__);
+ want_yvu = 0;
+/* Caching not used if byte seek */
+ byte_seek = -1;
+ return result;
+}
+
+int zvideo_t::
+colormodel()
+{
+ switch( chroma_format ) {
+ case cfmt_422: return cmdl_YUV422P; break;
+ case cfmt_420: return cmdl_YUV420P; break;
+ }
+ return cmdl_YUV420P;
+}
+
+zcc_t *zvideo_t::
+get_cc()
+{
+ if( !cc )
+ cc = new cc_t(this);
+ return cc;
+}
+
+void zvideo_t::
+reset_subtitles()
+{
+ for( int i=0; i<src->total_stracks; ++i ) {
+ strack_t *strack = src->strack[i];
+ if( strack->video != this ) continue;
+ strack->del_all_subtitles();
+ }
+}
+
+int zvideo_t::
+show_subtitle(int strk)
+{
+ int ret = subtitle_track;
+ if( subtitle_track != strk ) {
+ reset_subtitles();
+ subtitle_track = strk;
+ if( cc ) {
+ if( strk >= 0 ) cc->reset();
+ else { delete cc; cc = 0; }
+ }
+ }
+ return ret;
+}
+
+void zvideo_t::
+dump()
+{
+ zmsg("\n");
+ zmsg(" *** sequence extension 1\n");
+ zmsgs("prog_seq=%d\n", prog_seq);
+ zmsg(" *** picture header 1\n");
+ zmsgs("pict_type=%d field_sequence=%d\n", pict_type, field_sequence);
+ zmsg(" *** picture coding extension 1\n");
+ zmsgs("field_sequence=%d repeatfirst=%d prog_frame=%d pict_struct=%d\n",
+ field_sequence, repeatfirst, prog_frame, pict_struct);
+}
+