📄 dvbsub.c
字号:
break; } }#if DEBUG_DVBSUB msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries );#endif#ifndef RANDOM_DITHERING pi_delta = malloc( ( p_region->picture.p[0].i_pitch + 1 ) * sizeof(int) * 4 ); for( i = 0; i < (p_region->picture.p[0].i_pitch + 1) * 4 ; i++ ) { pi_delta[ i ] = 0; }#endif /* Fill image with our new colours */ for( p = 0; p < p_region->picture.p[0].i_visible_lines ; p++ ) { int i_ydelta = 0, i_udelta = 0, i_vdelta = 0, i_adelta = 0; for( n = 0; n < p_region->picture.p[0].i_pitch ; n++ ) { int i_offset = p * p_region->picture.p[0].i_pitch + n; int y, u, v, a; int i_mindist, i_best; y = (int)p_region->picture.p[0].p_pixels[i_offset]; u = (int)p_region->picture.p[1].p_pixels[i_offset]; v = (int)p_region->picture.p[2].p_pixels[i_offset]; a = (int)p_region->picture.p[3].p_pixels[i_offset]; /* Add dithering compensation */#ifdef RANDOM_DITHERING y += ((i_seed & 0xff) - 0x80) * i_tolerance / 0x80; u += (((i_seed >> 8) & 0xff) - 0x80) * i_tolerance / 0x80; v += (((i_seed >> 16) & 0xff) - 0x80) * i_tolerance / 0x80; a += (((i_seed >> 24) & 0xff) - 0x80) * i_tolerance / 0x80;#else y += i_ydelta + pi_delta[ n * 4 ]; u += i_udelta + pi_delta[ n * 4 + 1 ]; v += i_vdelta + pi_delta[ n * 4 + 2 ]; a += i_adelta + pi_delta[ n * 4 + 3 ];#endif /* Find best colour in palette */ for( i_mindist = 99999999, i_best = 0, j = 0; j < p_fmt->p_palette->i_entries; j++ ) { int i_dist = 0; i_dist += abs((int)p_fmt->p_palette->palette[j][0] - y); i_dist += abs((int)p_fmt->p_palette->palette[j][1] - u); i_dist += abs((int)p_fmt->p_palette->palette[j][2] - v); i_dist += 2 * abs((int)p_fmt->p_palette->palette[j][3] - a); if( i_dist < i_mindist ) { i_mindist = i_dist; i_best = j; } } /* Set pixel to best color */ p_region->picture.p[0].p_pixels[i_offset] = i_best; /* Update dithering state */#ifdef RANDOM_DITHERING i_seed = (i_seed * 0x1283837) ^ 0x789479 ^ (i_seed >> 13);#else i_ydelta = y - (int)p_fmt->p_palette->palette[i_best][0]; i_udelta = u - (int)p_fmt->p_palette->palette[i_best][1]; i_vdelta = v - (int)p_fmt->p_palette->palette[i_best][2]; i_adelta = a - (int)p_fmt->p_palette->palette[i_best][3]; pi_delta[ n * 4 ] = i_ydelta * 3 / 8; pi_delta[ n * 4 + 1 ] = i_udelta * 3 / 8; pi_delta[ n * 4 + 2 ] = i_vdelta * 3 / 8; pi_delta[ n * 4 + 3 ] = i_adelta * 3 / 8; i_ydelta = i_ydelta * 5 / 8; i_udelta = i_udelta * 5 / 8; i_vdelta = i_vdelta * 5 / 8; i_adelta = i_adelta * 5 / 8;#endif } }#ifndef RANDOM_DITHERING free( pi_delta );#endif /* pad palette */ for( i = p_fmt->p_palette->i_entries; i < i_max_entries; i++ ) { p_fmt->p_palette->palette[i][0] = 0; p_fmt->p_palette->palette[i][1] = 0; p_fmt->p_palette->palette[i][2] = 0; p_fmt->p_palette->palette[i][3] = 0; } p_fmt->p_palette->i_entries = i_max_entries;#if DEBUG_DVBSUB msg_Dbg( p_enc, "best palette has %d colors", p_fmt->p_palette->i_entries );#endif } return p_subpic;} /* End of hack *//**************************************************************************** * Encode: the whole thing ****************************************************************************/static block_t *Encode( encoder_t *p_enc, subpicture_t *p_subpic ){ subpicture_t *p_temp = NULL; subpicture_region_t *p_region = NULL; bs_t bits, *s = &bits; block_t *p_block; if( !p_subpic || !p_subpic->p_region ) return NULL; /* FIXME: this is a hack to convert VLC_FOURCC('Y','U','V','A') into * VLC_FOURCC('Y','U','V','P') */ p_region = p_subpic->p_region; if( p_region->fmt.i_chroma == VLC_FOURCC('Y','U','V','A') ) { p_temp = YuvaYuvp( p_enc, p_subpic ); if( !p_temp ) { msg_Err( p_enc, "no picture in subpicture" ); return NULL; } p_region = p_subpic->p_region; } /* Sanity check */ if( !p_region ) return NULL; if( p_region->fmt.i_chroma != VLC_FOURCC('T','E','X','T') && p_region->fmt.i_chroma != VLC_FOURCC('Y','U','V','P') ) return NULL; if( p_region->fmt.p_palette ) { switch( p_region->fmt.p_palette->i_entries ) { case 0: case 4: case 16: case 256: break; default: msg_Err( p_enc, "subpicture palette (%d) not handled", p_region->fmt.p_palette->i_entries ); return NULL; } } /* End of hack */#if DEBUG_DVBSUB msg_Dbg( p_enc, "encoding subpicture" );#endif p_block = block_New( p_enc, 64000 ); bs_init( s, p_block->p_buffer, p_block->i_buffer ); bs_write( s, 8, 0x20 ); /* Data identifier */ bs_write( s, 8, 0x0 ); /* Subtitle stream id */ encode_page_composition( p_enc, s, p_subpic ); encode_region_composition( p_enc, s, p_subpic ); encode_clut( p_enc, s, p_subpic ); encode_object( p_enc, s, p_subpic ); /* End of display */ bs_write( s, 8, 0x0f ); /* Sync byte */ bs_write( s, 8, DVBSUB_ST_ENDOFDISPLAY ); /* Segment type */ bs_write( s, 16, 1 ); /* Page id */ bs_write( s, 16, 0 ); /* Segment length */ bs_write( s, 8, 0xff );/* End marker */ p_block->i_buffer = bs_pos( s ) / 8; p_block->i_pts = p_block->i_dts = p_subpic->i_start; if( !p_subpic->b_ephemer && p_subpic->i_stop > p_subpic->i_start ) { block_t *p_block_stop; p_block->i_length = p_subpic->i_stop - p_subpic->i_start; /* Send another (empty) subtitle to signal the end of display */ p_block_stop = block_New( p_enc, 64000 ); bs_init( s, p_block_stop->p_buffer, p_block_stop->i_buffer ); bs_write( s, 8, 0x20 ); /* Data identifier */ bs_write( s, 8, 0x0 ); /* Subtitle stream id */ encode_page_composition( p_enc, s, 0 ); bs_write( s, 8, 0x0f ); /* Sync byte */ bs_write( s, 8, DVBSUB_ST_ENDOFDISPLAY ); /* Segment type */ bs_write( s, 16, 1 ); /* Page id */ bs_write( s, 16, 0 ); /* Segment length */ bs_write( s, 8, 0xff );/* End marker */ p_block_stop->i_buffer = bs_pos( s ) / 8; p_block_stop->i_pts = p_block_stop->i_dts = p_subpic->i_stop; block_ChainAppend( &p_block, p_block_stop ); p_block_stop->i_length = 100000; /* p_subpic->i_stop - p_subpic->i_start; */ }#ifdef DEBUG_DVBSUB msg_Dbg( p_enc, "subpicture encoded properly" );#endif return p_block;}/***************************************************************************** * CloseEncoder: encoder destruction *****************************************************************************/static void CloseEncoder( vlc_object_t *p_this ){ encoder_t *p_enc = (encoder_t *)p_this; encoder_sys_t *p_sys = p_enc->p_sys; var_Destroy( p_this , ENC_CFG_PREFIX "x" ); var_Destroy( p_this , ENC_CFG_PREFIX "y" ); var_Destroy( p_this , ENC_CFG_PREFIX "timeout" ); if( p_sys->i_regions ) free( p_sys->p_regions ); free( p_sys );}static void encode_page_composition( encoder_t *p_enc, bs_t *s, subpicture_t *p_subpic ){ encoder_sys_t *p_sys = p_enc->p_sys; subpicture_region_t *p_region; vlc_bool_t b_mode_change = VLC_FALSE; int i_regions, i_timeout; bs_write( s, 8, 0x0f ); /* Sync byte */ bs_write( s, 8, DVBSUB_ST_PAGE_COMPOSITION ); /* Segment type */ bs_write( s, 16, 1 ); /* Page id */ for( i_regions = 0, p_region = p_subpic ? p_subpic->p_region : 0; p_region; p_region = p_region->p_next, i_regions++ ) { if( i_regions >= p_sys->i_regions ) { encoder_region_t region; region.i_width = region.i_height = 0; p_sys->p_regions = realloc( p_sys->p_regions, sizeof(encoder_region_t) * (p_sys->i_regions + 1) ); p_sys->p_regions[p_sys->i_regions++] = region; } if( ( p_sys->p_regions[i_regions].i_width < (int)p_region->fmt.i_visible_width ) || ( p_sys->p_regions[i_regions].i_width > (int)p_region->fmt.i_visible_width ) ) { b_mode_change = VLC_TRUE; msg_Dbg( p_enc, "region %i width change: %i -> %i", i_regions, p_sys->p_regions[i_regions].i_width, p_region->fmt.i_visible_width ); p_sys->p_regions[i_regions].i_width = p_region->fmt.i_visible_width; } if( p_sys->p_regions[i_regions].i_height < (int)p_region->fmt.i_visible_height ) { b_mode_change = VLC_TRUE; msg_Dbg( p_enc, "region %i height change: %i -> %i", i_regions, p_sys->p_regions[i_regions].i_height, p_region->fmt.i_visible_height ); p_sys->p_regions[i_regions].i_height = p_region->fmt.i_visible_height; } } bs_write( s, 16, i_regions * 6 + 2 ); /* Segment length */ i_timeout = 0; if( p_subpic && !p_subpic->b_ephemer && p_subpic->i_stop > p_subpic->i_start ) { i_timeout = (p_subpic->i_stop - p_subpic->i_start) / 1000000; } bs_write( s, 8, i_timeout ); /* Timeout */ bs_write( s, 4, p_sys->i_page_ver++ ); bs_write( s, 2, b_mode_change ? DVBSUB_PCS_STATE_CHANGE : DVBSUB_PCS_STATE_ACQUISITION ); bs_write( s, 2, 0 ); /* Reserved */ for( i_regions = 0, p_region = p_subpic ? p_subpic->p_region : 0; p_region; p_region = p_region->p_next, i_regions++ ) { bs_write( s, 8, i_regions ); bs_write( s, 8, 0 ); /* Reserved */ if( (p_sys->i_offset_x > 0) && (p_sys->i_offset_y > 0) ) { bs_write( s, 16, p_sys->i_offset_x ); /* override x position */ bs_write( s, 16, p_sys->i_offset_y ); /* override y position */ } else { bs_write( s, 16, p_subpic->i_x + p_region->i_x ); bs_write( s, 16, p_subpic->i_y + p_region->i_y ); } }}static void encode_clut( encoder_t *p_enc, bs_t *s, subpicture_t *p_subpic ){ encoder_sys_t *p_sys = p_enc->p_sys; subpicture_region_t *p_region = p_subpic->p_region; video_palette_t *p_pal, pal; int i; /* Sanity check */ if( !p_region ) return; if( p_region->fmt.i_chroma == VLC_FOURCC('Y','U','V','P') ) { p_pal = p_region->fmt.p_palette; } else { pal.i_entries = 4; for( i = 0; i < 4; i++ ) { pal.palette[i][0] = 0; pal.palette[i][1] = 0; pal.palette[i][2] = 0; pal.palette[i][3] = 0; } p_pal = &pal; } bs_write( s, 8, 0x0f ); /* Sync byte */ bs_write( s, 8, DVBSUB_ST_CLUT_DEFINITION ); /* Segment type */ bs_write( s, 16, 1 ); /* Page id */ bs_write( s, 16, p_pal->i_entries * 6 + 2 ); /* Segment length */ bs_write( s, 8, 1 ); /* Clut id */ bs_write( s, 4, p_sys->i_clut_ver++ ); bs_write( s, 4, 0 ); /* Reserved */ for( i = 0; i < p_pal->i_entries; i++ ) { bs_write( s, 8, i ); /* Clut entry id */ bs_write( s, 1, p_pal->i_entries == 4 ); /* 2bit/entry flag */ bs_write( s, 1, p_pal->i_entries == 16 ); /* 4bit/entry flag */ bs_write( s, 1, p_pal->i_entries == 256 ); /* 8bit/entry flag */ bs_write( s, 4, 0 ); /* Reserved */ bs_write( s, 1, 1 ); /* Full range flag */ bs_write( s, 8, p_pal->palette[i][3] ? /* Y value */ (p_pal->palette[i][0] ? p_pal->palette[i][0] : 16) : 0 ); bs_write( s, 8, p_pal->palette[i][1] ); /* Cr value */ bs_write( s, 8, p_pal->palette[i][2] ); /* Cb value */ bs_write( s, 8, 0xff - p_pal->palette[i][3] ); /* T value */ }}static void encode_region_composition( encoder_t *p_enc, bs_t *s, subpicture_t *p_subpic ){ encoder_sys_t *p_sys = p_enc->p_sys; subpicture_region_t *p_region; int i_region; for( i_region = 0, p_region = p_subpic->p_region; p_region; p_region = p_region->p_next, i_region++ ) { int i_entries = 4, i_depth = 0x1, i_bg = 0; vlc_bool_t b_text = p_region->fmt.i_chroma == VLC_FOURCC('T','E','X','T'); if( !b_text ) { video_palette_t *p_pal = p_region->fmt.p_palette; if( !p_pal ) { msg_Err( p_enc, "subpicture has no palette - ignoring it" ); break; } i_entries = p_pal->i_entries; i_depth = i_entries == 4 ? 0x1 : i_entries == 16 ? 0x2 : 0x3; for( i_bg = 0; i_bg < p_pal->i_entries; i_bg++ ) { if( !p_pal->palette[i_bg][3] ) break; } } bs_write( s, 8, 0x0f ); /* Sync byte */ bs_write( s, 8, DVBSUB_ST_REGION_COMPOSITION ); /* Segment type */ bs_write( s, 16, 1 ); /* Page id */ bs_write( s, 16, 10 + 6 + (b_text ? 2 : 0) ); /* Segment length */ bs_write( s, 8, i_region ); bs_write( s, 4, p_sys->i_region_ver++ ); /* Region attributes */ bs_write( s, 1, i_bg < i_entries ); /* Fill */ bs_write( s, 3, 0 ); /* Reserved */ bs_write( s, 16, p_sys->p_regions[i_region].i_width ); bs_write( s, 16, p_sys->p_regions[i_region].i_height ); bs_write( s, 3, i_depth ); /* Region level of compatibility */ bs_write( s, 3, i_depth ); /* Region depth */ bs_write( s, 2, 0 ); /* Reserved */ bs_write( s, 8, 1 ); /* Clut id */ bs_write( s, 8, i_bg ); /* region 8bit pixel code */ bs_write( s, 4, i_bg ); /* region 4bit pixel code */ bs_write( s, 2, i_bg ); /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -