📄 svcdsub.c
字号:
return NULL; } } if( p_sys->i_state == SUBTITLE_BLOCK_EMPTY ) { i_expected_image = p_sys->i_image + 1; i_expected_packet = 0; } else { i_expected_image = p_sys->i_image; i_expected_packet = p_sys->i_packet + 1; } p_buffer += 2; if( *p_buffer & 0x80 ) { p_sys->i_state = SUBTITLE_BLOCK_COMPLETE; i_packet = *p_buffer++ & 0x7F; } else { p_sys->i_state = SUBTITLE_BLOCK_PARTIAL; i_packet = *p_buffer++; } p_sys->i_image = GETINT16(p_buffer); if( p_sys->i_image != i_expected_image ) { msg_Warn( p_dec, "expected subtitle image %u but found %u", i_expected_image, p_sys->i_image ); } if( i_packet != i_expected_packet ) { msg_Warn( p_dec, "expected subtitle image packet %u but found %u", i_expected_packet, i_packet ); } p_block->p_buffer += SPU_HEADER_LEN; p_block->i_buffer -= SPU_HEADER_LEN; p_sys->i_packet = i_packet; /* First packet in the subtitle block */ if( !p_sys->i_packet ) ParseHeader( p_dec, p_block ); block_ChainAppend( &p_sys->p_spu, p_block ); if( p_sys->i_state == SUBTITLE_BLOCK_COMPLETE ) { block_t *p_spu = block_ChainGather( p_sys->p_spu ); if( p_spu->i_buffer != p_sys->i_spu_size ) { msg_Warn( p_dec, "subtitle packets size=%d should be %d", p_spu->i_buffer, p_sys->i_spu_size ); } dbg_print( (DECODE_DBG_PACKET), "subtitle packet complete, size=%d", p_spu->i_buffer ); p_sys->i_state = SUBTITLE_BLOCK_EMPTY; p_sys->p_spu = 0; return p_spu; } return NULL;}/****************************************************************************** The format is roughly as follows (everything is big-endian): size description ------------------------------------------- byte subtitle channel (0..7) in bits 0-3 byte subtitle packet number of this subtitle image 0-N, if the subtitle packet is complete, the top bit of the byte is 1. u_int16 subtitle image number u_int16 length in bytes of the rest byte option flags, unknown meaning except bit 3 (0x08) indicates presence of the duration field byte unknown u_int32 duration in 1/90000ths of a second (optional), start time is as indicated by the PTS in the PES header u_int32 xpos u_int32 ypos u_int32 width (must be even) u_int32 height (must be even) byte[16] palette, 4 palette entries, each contains values for Y, U, V and transparency, 0 standing for transparent byte command, cmd>>6==1 indicates shift (cmd>>4)&3 is direction from, (0=top,1=left,2=right,3=bottom) u_int32 shift duration in 1/90000ths of a second u_int16 offset of odd-numbered scanlines - subtitle images are given in interlace order byte[] limited RLE image data in interlace order (0,2,4... 1,3,5) with 2-bits per palette number******************************************************************************/static void ParseHeader( decoder_t *p_dec, block_t *p_block ){ decoder_sys_t *p_sys = p_dec->p_sys; uint8_t *p = p_block->p_buffer; uint8_t i_options, i_options2, i_cmd, i_cmd_arg; int i; p_sys->i_spu_size = GETINT16(p); i_options = *p++; i_options2 = *p++; if( i_options & 0x08 ) { p_sys->i_duration = GETINT32(p); } else p_sys->i_duration = 0; /* Ephemer subtitle */ p_sys->i_duration *= 100 / 9; p_sys->i_x_start = GETINT16(p); p_sys->i_y_start = GETINT16(p); p_sys->i_width = GETINT16(p); p_sys->i_height = GETINT16(p); for( i = 0; i < 4; i++ ) { p_sys->p_palette[i][0] = *p++; /* Y */ p_sys->p_palette[i][2] = *p++; /* Cr / V */ p_sys->p_palette[i][1] = *p++; /* Cb / U */ p_sys->p_palette[i][3] = *p++; /* T */ } i_cmd = *p++; /* We do not really know this, FIXME */ if( i_cmd ) {i_cmd_arg = GETINT32(p);} /* Actually, this is measured against a different origin, so we have to * adjust it */ p_sys->second_field_offset = GETINT16(p); p_sys->i_image_offset = p - p_block->p_buffer; p_sys->i_image_length = p_sys->i_spu_size - p_sys->i_image_offset; p_sys->metadata_length = p_sys->i_image_offset; if (p_sys && p_sys->i_debug & DECODE_DBG_PACKET) { msg_Dbg( p_dec, "x-start: %d, y-start: %d, width: %d, height %d, " "spu size: %d, duration: %lu (d:%d p:%d)", p_sys->i_x_start, p_sys->i_y_start, p_sys->i_width, p_sys->i_height, p_sys->i_spu_size, (long unsigned int) p_sys->i_duration, p_sys->i_image_length, p_sys->i_image_offset); for( i = 0; i < 4; i++ ) { msg_Dbg( p_dec, "palette[%d]= T: %2x, Y: %2x, u: %2x, v: %2x", i, p_sys->p_palette[i][3], p_sys->p_palette[i][0], p_sys->p_palette[i][1], p_sys->p_palette[i][2] ); } }}/***************************************************************************** * DecodePacket: parse and decode an subtitle packet ***************************************************************************** * This function parses and decodes an SPU packet and, if valid, returns a * subpicture. *****************************************************************************/static subpicture_t *DecodePacket( decoder_t *p_dec, block_t *p_data ){ decoder_sys_t *p_sys = p_dec->p_sys; subpicture_t *p_spu; subpicture_region_t *p_region; video_format_t fmt; int i; /* Allocate the subpicture internal data. */ p_spu = p_dec->pf_spu_buffer_new( p_dec ); if( !p_spu ) return NULL; p_spu->b_pausable = VLC_TRUE; p_spu->i_x = p_sys->i_x_start; p_spu->i_y = p_sys->i_y_start; p_spu->i_start = p_data->i_pts; p_spu->i_stop = p_data->i_pts + p_sys->i_duration; p_spu->b_ephemer = VLC_TRUE; /* Create new subtitle region */ memset( &fmt, 0, sizeof(video_format_t) ); fmt.i_chroma = VLC_FOURCC('Y','U','V','P'); /** The video on which the subtitle sits, is scaled, probably 4:3. However subtitle bitmaps assume an 1:1 aspect ratio. FIXME: We should get the video aspect ratio from somewhere. Two candidates are the video and the other possibility would be the access module. */ fmt.i_aspect = VOUT_ASPECT_FACTOR; fmt.i_width = fmt.i_visible_width = p_sys->i_width; fmt.i_height = fmt.i_visible_height = p_sys->i_height; fmt.i_x_offset = fmt.i_y_offset = 0; p_region = p_spu->pf_create_region( VLC_OBJECT(p_dec), &fmt ); if( !p_region ) { msg_Err( p_dec, "cannot allocate SVCD subtitle region" ); //goto error; } p_region->fmt.i_aspect = VOUT_ASPECT_FACTOR; p_spu->p_region = p_region; p_region->i_x = p_region->i_y = 0; /* Build palette */ fmt.p_palette->i_entries = 4; for( i = 0; i < fmt.p_palette->i_entries; i++ ) { fmt.p_palette->palette[i][0] = p_sys->p_palette[i][0]; fmt.p_palette->palette[i][1] = p_sys->p_palette[i][1]; fmt.p_palette->palette[i][2] = p_sys->p_palette[i][2]; fmt.p_palette->palette[i][3] = p_sys->p_palette[i][3]; } SVCDSubRenderImage( p_dec, p_data, p_region ); return p_spu;}/***************************************************************************** * SVCDSubRenderImage: reorders bytes of image data in subpicture region. ***************************************************************************** The image is encoded using two bits per pixel that select a palette entry except that value 0 starts a limited run-length encoding for color 0. When 0 is seen, the next two bits encode one less than the number of pixels, so we can encode run lengths from 1 to 4. These get filled with the color in palette entry 0. The encoding of each line is padded to a whole number of bytes. The first field is padded to an even byte length and the complete subtitle is padded to a 4-byte multiple that always include one zero byte at the end. However we'll transform this so that that the RLE is expanded and interlacing will also be removed. *****************************************************************************/static void SVCDSubRenderImage( decoder_t *p_dec, block_t *p_data, subpicture_region_t *p_region ){ decoder_sys_t *p_sys = p_dec->p_sys; uint8_t *p_dest = p_region->picture.Y_PIXELS; int i_field; /* The subtitles are interlaced */ int i_row, i_column; /* scanline row/column number */ uint8_t i_color, i_count; bs_t bs; bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset, p_data->i_buffer - p_sys->i_image_offset ); for( i_field = 0; i_field < 2; i_field++ ) { for( i_row = i_field; i_row < p_sys->i_height; i_row += 2 ) { for( i_column = 0; i_column < p_sys->i_width; i_column++ ) { i_color = bs_read( &bs, 2 ); if( i_color == 0 && (i_count = bs_read( &bs, 2 )) ) { i_count = __MIN( i_count, p_sys->i_width - i_column ); memset( &p_dest[i_row * p_region->picture.Y_PITCH + i_column], 0, i_count + 1 ); i_column += i_count; continue; } p_dest[i_row * p_region->picture.Y_PITCH + i_column] = i_color; } bs_align( &bs ); } /* odd field */ bs_init( &bs, p_data->p_buffer + p_sys->i_image_offset + p_sys->second_field_offset, p_data->i_buffer - p_sys->i_image_offset - p_sys->second_field_offset ); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -