📄 dvbsub.c
字号:
/* Check version number */ if( p_region && ( p_region->i_version == i_version ) ) { bs_skip( s, 8 * (i_segment_length - 1) - 4 ); return; } if( !p_region ) {#ifdef DEBUG_DVBSUB msg_Dbg( p_dec, "new region: %i", i_id );#endif p_region = *pp_region = malloc( sizeof(dvbsub_region_t) ); if( p_region ) { memset( p_region, 0, sizeof(dvbsub_region_t) ); p_region->p_object_defs = NULL; p_region->p_pixbuf = NULL; p_region->p_next = NULL; } } /* Region attributes */ p_region->i_id = i_id; p_region->i_version = i_version; b_fill = bs_read( s, 1 ); bs_skip( s, 3 ); /* Reserved */ i_width = bs_read( s, 16 ); i_height = bs_read( s, 16 );#ifdef DEBUG_DVBSUB msg_Dbg( p_dec, " width=%d height=%d", i_width, i_height );#endif i_level_comp = bs_read( s, 3 ); i_depth = bs_read( s, 3 ); bs_skip( s, 2 ); /* Reserved */ i_clut = bs_read( s, 8 ); i_8_bg = bs_read( s, 8 ); i_4_bg = bs_read( s, 4 ); i_2_bg = bs_read( s, 2 ); bs_skip( s, 2 ); /* Reserved */ /* Free old object defs */ while( p_region->i_object_defs ) free( p_region->p_object_defs[--p_region->i_object_defs].psz_text ); free( p_region->p_object_defs ); p_region->p_object_defs = NULL; /* Extra sanity checks */ if( ( p_region->i_width != i_width ) || ( p_region->i_height != i_height ) ) { if( p_region->p_pixbuf ) { msg_Dbg( p_dec, "region size changed (%dx%d->%dx%d)", p_region->i_width, p_region->i_height, i_width, i_height ); free( p_region->p_pixbuf ); } p_region->p_pixbuf = malloc( i_height * i_width ); p_region->i_depth = 0; b_fill = true; } if( p_region->i_depth && ( ( p_region->i_depth != i_depth ) || ( p_region->i_level_comp != i_level_comp ) || ( p_region->i_clut != i_clut) ) ) { msg_Dbg( p_dec, "region parameters changed (not allowed)" ); } /* Erase background of region */ if( b_fill ) { int i_background = ( p_region->i_depth == 1 ) ? i_2_bg : ( ( p_region->i_depth == 2 ) ? i_4_bg : i_8_bg ); memset( p_region->p_pixbuf, i_background, i_width * i_height ); } p_region->i_width = i_width; p_region->i_height = i_height; p_region->i_level_comp = i_level_comp; p_region->i_depth = i_depth; p_region->i_clut = i_clut; /* List of objects in the region */ i_processed_length = 10; while( i_processed_length < i_segment_length ) { dvbsub_objectdef_t *p_obj; /* We create a new object */ p_region->i_object_defs++; p_region->p_object_defs = realloc( p_region->p_object_defs, sizeof(dvbsub_objectdef_t) * p_region->i_object_defs ); /* We parse object properties */ p_obj = &p_region->p_object_defs[p_region->i_object_defs - 1]; p_obj->i_id = bs_read( s, 16 ); p_obj->i_type = bs_read( s, 2 ); bs_skip( s, 2 ); /* Provider */ p_obj->i_x = bs_read( s, 12 ); bs_skip( s, 4 ); /* Reserved */ p_obj->i_y = bs_read( s, 12 ); p_obj->psz_text = 0; i_processed_length += 6; if( ( p_obj->i_type == DVBSUB_OT_BASIC_CHAR ) || ( p_obj->i_type == DVBSUB_OT_COMPOSITE_STRING ) ) { p_obj->i_fg_pc = bs_read( s, 8 ); p_obj->i_bg_pc = bs_read( s, 8 ); i_processed_length += 2; } }}/* ETSI 300 743 [7.2.1] */static void decode_display_definition( decoder_t *p_dec, bs_t *s ){ decoder_sys_t *p_sys = p_dec->p_sys; uint16_t i_segment_length; uint16_t i_processed_length = 40; dvbsub_display_t *p_display; dvbsub_display_t *p_old = p_sys->p_display; int i_version; i_segment_length = bs_read( s, 16 ); i_version = bs_read( s, 4 ); /* Check version number */ if( p_old && ( p_old->i_version == i_version ) ) { /* The definition did not change */ bs_skip( s, 8*i_segment_length - 4 ); return; }#ifdef DEBUG_DVBSUB msg_Dbg( p_dec, "new display definition: %i", i_version );#endif p_display = malloc( sizeof(dvbsub_display_t) ); if( p_display ) { /* We don't have this version of the display definition: Parse it */ p_display->i_version = i_version; p_display->b_windowed = bs_read( s, 1 ); bs_skip( s, 3 ); /* Reserved bits */ p_display->i_width = bs_read( s, 16 )+1; p_display->i_height = bs_read( s, 16 )+1; if( p_display->b_windowed ) {#ifdef DEBUG_DVBSUB msg_Dbg( p_dec, "display definition with offsets (windowed)" );#endif /* Coordinates are measured from the top left corner */ p_display->i_x = bs_read( s, 16 ); p_display->i_max_x = bs_read( s, 16 ); p_display->i_y = bs_read( s, 16 ); p_display->i_max_y = bs_read( s, 16 ); i_processed_length += 64; } } p_sys->p_display = p_display; free( p_old ); if( i_processed_length != i_segment_length*8 ) { msg_Err( p_dec, "processed length %d != segment length %d", i_processed_length, i_segment_length ); }#ifdef DEBUG_DVBSUB msg_Dbg( p_dec, "version: %d, width: %d, height: %d", p_display->i_version, p_display->i_width, p_display->i_height ); if( p_display->b_windowed ) msg_Dbg( p_dec, "xmin: %d, xmax: %d, ymin: %d, ymax: %d", p_display->i_x, p_display->i_max_x, p_display->i_y, p_display->i_max_y );#endif}static void dvbsub_render_pdata( decoder_t *, dvbsub_region_t *, int, int, uint8_t *, int );static void dvbsub_pdata2bpp( bs_t *, uint8_t *, int, int * );static void dvbsub_pdata4bpp( bs_t *, uint8_t *, int, int * );static void dvbsub_pdata8bpp( bs_t *, uint8_t *, int, int * );static void decode_object( decoder_t *p_dec, bs_t *s ){ decoder_sys_t *p_sys = p_dec->p_sys; dvbsub_region_t *p_region; int i_segment_length, i_coding_method, i_version, i_id, i; bool b_non_modify_color; /* ETSI 300-743 paragraph 7.2.4 * sync_byte, segment_type and page_id have already been processed. */ i_segment_length = bs_read( s, 16 ); i_id = bs_read( s, 16 ); i_version = bs_read( s, 4 ); i_coding_method = bs_read( s, 2 ); if( i_coding_method > 1 ) { msg_Dbg( p_dec, "unknown DVB subtitling coding %d is not handled!", i_coding_method ); bs_skip( s, 8 * (i_segment_length - 2) - 6 ); return; } /* Check if the object needs to be rendered in at least one * of the regions */ for( p_region = p_sys->p_regions; p_region != NULL; p_region = p_region->p_next ) { for( i = 0; i < p_region->i_object_defs; i++ ) if( p_region->p_object_defs[i].i_id == i_id ) break; if( i != p_region->i_object_defs ) break; } if( !p_region ) { bs_skip( s, 8 * (i_segment_length - 2) - 6 ); return; }#ifdef DEBUG_DVBSUB msg_Dbg( p_dec, "new object: %i", i_id );#endif b_non_modify_color = bs_read( s, 1 ); bs_skip( s, 1 ); /* Reserved */ if( i_coding_method == 0x00 ) { int i_topfield, i_bottomfield; uint8_t *p_topfield, *p_bottomfield; i_topfield = bs_read( s, 16 ); i_bottomfield = bs_read( s, 16 ); p_topfield = s->p_start + bs_pos( s ) / 8; p_bottomfield = p_topfield + i_topfield; bs_skip( s, 8 * (i_segment_length - 7) ); /* Sanity check */ if( ( i_segment_length < ( i_topfield + i_bottomfield + 7 ) ) || ( ( p_topfield + i_topfield + i_bottomfield ) > s->p_end ) ) { msg_Dbg( p_dec, "corrupted object data" ); return; } for( p_region = p_sys->p_regions; p_region != NULL; p_region = p_region->p_next ) { for( i = 0; i < p_region->i_object_defs; i++ ) { if( p_region->p_object_defs[i].i_id != i_id ) continue; dvbsub_render_pdata( p_dec, p_region, p_region->p_object_defs[i].i_x, p_region->p_object_defs[i].i_y, p_topfield, i_topfield ); if( i_bottomfield ) { dvbsub_render_pdata( p_dec, p_region, p_region->p_object_defs[i].i_x, p_region->p_object_defs[i].i_y + 1, p_bottomfield, i_bottomfield ); } else { /* Duplicate the top field */ dvbsub_render_pdata( p_dec, p_region, p_region->p_object_defs[i].i_x, p_region->p_object_defs[i].i_y + 1, p_topfield, i_topfield ); } } } } else { /* DVB subtitling as characters */ int i_number_of_codes = bs_read( s, 8 ); uint8_t* p_start = s->p_start + bs_pos( s ) / 8; /* Sanity check */ if( ( i_segment_length < ( i_number_of_codes*2 + 4 ) ) || ( ( p_start + i_number_of_codes*2 ) > s->p_end ) ) { msg_Dbg( p_dec, "corrupted object data" ); return; } for( p_region = p_sys->p_regions; p_region != NULL; p_region = p_region->p_next ) { for( i = 0; i < p_region->i_object_defs; i++ ) { int j; if( p_region->p_object_defs[i].i_id != i_id ) continue; p_region->p_object_defs[i].psz_text = realloc( p_region->p_object_defs[i].psz_text, i_number_of_codes + 1 ); /* FIXME 16bits -> char ??? See Preamble */ for( j = 0; j < i_number_of_codes; j++ ) { p_region->p_object_defs[i].psz_text[j] = (char)(bs_read( s, 16 ) & 0xFF); } /* Null terminate the string */ p_region->p_object_defs[i].psz_text[j] = 0; } } }#ifdef DEBUG_DVBSUB msg_Dbg( p_dec, "end object: %i", i_id );#endif}static void dvbsub_render_pdata( decoder_t *p_dec, dvbsub_region_t *p_region, int i_x, int i_y, uint8_t *p_field, int i_field ){ uint8_t *p_pixbuf; int i_offset = 0; bs_t bs; /* Sanity check */ if( !p_region->p_pixbuf ) { msg_Err( p_dec, "region %i has no pixel buffer!", p_region->i_id ); return; } if( i_y < 0 || i_x < 0 || i_y >= p_region->i_height || i_x >= p_region->i_width ) { msg_Dbg( p_dec, "invalid offset (%i,%i)", i_x, i_y ); return; } p_pixbuf = p_region->p_pixbuf + i_y * p_region->i_width; bs_init( &bs, p_field, i_field ); while( !bs_eof( &bs ) ) { /* Sanity check */ if( i_y >= p_region->i_height ) return; switch( bs_read( &bs, 8 ) ) { case 0x10: dvbsub_pdata2bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x, &i_offset ); break; case 0x11: dvbsub_pdata4bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x, &i_offset ); break; case 0x12: dvbsub_pdata8bpp( &bs, p_pixbuf + i_x, p_region->i_width - i_x, &i_offset ); break; case 0x20: case 0x21: case 0x22: /* We don't use map tables */ break; case 0xf0: /* End of line code */ p_pixbuf += 2*p_region->i_width; i_offset = 0; i_y += 2; break; } }}static void dvbsub_pdata2bpp( bs_t *s, uint8_t *p, int i_width, int *pi_off ){ bool b_stop = false; while( !b_stop && !bs_eof( s ) ) { int i_count = 0, i_color = 0; i_color = bs_read( s, 2 ); if( i_color != 0x00 ) { i_count = 1; } else { if( bs_read( s, 1 ) == 0x01 ) // Switch1 { i_count = 3 + bs_read( s, 3 ); i_color = bs_read( s, 2 ); } else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -