X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fkate.c;h=7f697bdf8759d288bae5a1b60e8ccffd00cd6baf;hb=12ade3e3bc975d5426ba4af155b7372c31093b31;hp=b85bf2e7c17b1f978d36cbb04ac6a14c1a76436c;hpb=152b1687c0ec112f3ab1360006d048d6b9cf7258;p=vlc diff --git a/modules/codec/kate.c b/modules/codec/kate.c index b85bf2e7c1..7f697bdf87 100644 --- a/modules/codec/kate.c +++ b/modules/codec/kate.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include "../demux/xiph.h" #include #ifdef HAVE_TIGER @@ -73,8 +73,7 @@ struct decoder_sys_t /* * Input properties */ - int i_num_headers; - int i_headers; + bool b_has_headers; /* * Kate properties @@ -88,6 +87,7 @@ struct decoder_sys_t * Common properties */ mtime_t i_pts; + mtime_t i_max_stop; /* decoder_sys_t is shared between decoder and spu units */ vlc_mutex_t lock; @@ -98,8 +98,6 @@ struct decoder_sys_t * Tiger properties */ tiger_renderer *p_tr; - subpicture_t *p_spu_final; - mtime_t last_render_ts; bool b_dirty; uint32_t i_tiger_default_font_color; @@ -117,7 +115,7 @@ struct decoder_sys_t bool b_use_tiger; }; -struct subpicture_sys_t +struct subpicture_updater_sys_t { decoder_sys_t *p_dec_sys; mtime_t i_start; @@ -344,7 +342,6 @@ static int OpenDecoder( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; - int i_ret; if( p_dec->fmt_in.i_codec != VLC_CODEC_KATE ) { @@ -372,13 +369,13 @@ static int OpenDecoder( vlc_object_t *p_this ) p_sys->b_packetizer = false; #endif p_sys->b_ready = false; - p_sys->i_pts = 0; + p_sys->i_pts = + p_sys->i_max_stop = VLC_TS_INVALID; kate_comment_init( &p_sys->kc ); kate_info_init( &p_sys->ki ); - p_sys->i_num_headers = 0; - p_sys->i_headers = 0; + p_sys->b_has_headers = false; /* retrieve options */ p_sys->b_formatted = var_CreateGetBool( p_dec, "kate-formatted" ); @@ -390,7 +387,6 @@ static int OpenDecoder( vlc_object_t *p_this ) p_sys->b_use_tiger = var_CreateGetBool( p_dec, "kate-use-tiger" ); p_sys->p_tr = NULL; - p_sys->last_render_ts = 0; /* get initial value of configuration */ p_sys->i_tiger_default_font_color = GetTigerColor( p_dec, "kate-tiger-default-font" ); @@ -402,7 +398,7 @@ static int OpenDecoder( vlc_object_t *p_this ) if( p_sys->b_use_tiger ) { - i_ret = tiger_renderer_create( &p_sys->p_tr ); + int i_ret = tiger_renderer_create( &p_sys->p_tr ); if( i_ret < 0 ) { msg_Warn ( p_dec, "Failed to create Tiger renderer, falling back to basic rendering" ); @@ -473,20 +469,18 @@ static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) p_block = *pp_block; - if( p_block->i_flags & (BLOCK_FLAG_CORRUPTED) ) - { - block_Release( p_block ); - return NULL; - } - - if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY) ) + if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { #ifdef HAVE_TIGER - /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */ - vlc_mutex_lock( &p_sys->lock ); - tiger_renderer_seek( p_sys->p_tr, 0 ); - vlc_mutex_unlock( &p_sys->lock ); + if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY) + { + /* Hmm, should we wait before flushing the renderer ? I think not, but not certain... */ + vlc_mutex_lock( &p_sys->lock ); + tiger_renderer_seek( p_sys->p_tr, 0 ); + vlc_mutex_unlock( &p_sys->lock ); + } #endif + p_sys->i_max_stop = VLC_TS_INVALID; block_Release( p_block ); return NULL; } @@ -494,42 +488,14 @@ static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) /* Block to Kate packet */ kate_packet_wrap(&kp, p_block->i_buffer, p_block->p_buffer); - if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra ) - { - /* Headers already available as extra data */ - p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0]; - p_sys->i_headers = p_sys->i_num_headers; - } - else if( kp.nbytes && (p_sys->i_headers==0 || p_sys->i_headers < p_sys->ki.num_headers )) - { - /* Backup headers as extra data */ - uint8_t *p_extra; - - p_dec->fmt_in.p_extra = - realloc( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra + kp.nbytes + 2 ); - p_extra = (void*)(((unsigned char*)p_dec->fmt_in.p_extra) + p_dec->fmt_in.i_extra); - *(p_extra++) = kp.nbytes >> 8; - *(p_extra++) = kp.nbytes & 0xFF; - - memcpy( p_extra, kp.data, kp.nbytes ); - p_dec->fmt_in.i_extra += kp.nbytes + 2; - - block_Release( *pp_block ); - p_sys->i_num_headers = ((unsigned char*)p_dec->fmt_in.p_extra)[0]; - p_sys->i_headers++; - return NULL; - } - - if( p_sys->i_headers == p_sys->i_num_headers && p_sys->i_num_headers>0 ) + if( !p_sys->b_has_headers ) { - if( ProcessHeaders( p_dec ) != VLC_SUCCESS ) + if( ProcessHeaders( p_dec ) ) { - p_sys->i_headers = 0; - p_dec->fmt_in.i_extra = 0; block_Release( *pp_block ); return NULL; } - else p_sys->i_headers++; + p_sys->b_has_headers = true; } return ProcessPacket( p_dec, &kp, pp_block ); @@ -542,37 +508,28 @@ static int ProcessHeaders( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; kate_packet kp; - uint8_t *p_extra; - int i_extra; - int i_headeridx; - int i_ret; - if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC; - - p_extra = p_dec->fmt_in.p_extra; - i_extra = p_dec->fmt_in.i_extra; - - /* skip number of headers */ - ++p_extra; - --i_extra; - - /* Take care of the initial Kate header */ - kp.nbytes = *(p_extra++) << 8; - kp.nbytes |= (*(p_extra++) & 0xFF); - kp.data = p_extra; - p_extra += kp.nbytes; - i_extra -= (kp.nbytes + 2); - if( i_extra < 0 ) - { - msg_Err( p_dec, "header data corrupted"); + unsigned pi_size[XIPH_MAX_HEADER_COUNT]; + void *pp_data[XIPH_MAX_HEADER_COUNT]; + unsigned i_count; + if( xiph_SplitHeaders( pi_size, pp_data, &i_count, + p_dec->fmt_in.i_extra, p_dec->fmt_in.p_extra) ) return VLC_EGENERIC; + int i_ret = VLC_SUCCESS; + if( i_count < 1 ) + { + i_ret = VLC_EGENERIC; + goto end; } + /* Take care of the initial Kate header */ + kp.nbytes = pi_size[0]; + kp.data = pp_data[0]; i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp ); if( i_ret < 0 ) { msg_Err( p_dec, "this bitstream does not contain Kate data (%d)", i_ret ); - return VLC_EGENERIC; + goto end; } msg_Dbg( p_dec, "%s %s text, granule rate %f, granule shift %d", @@ -581,24 +538,15 @@ static int ProcessHeaders( decoder_t *p_dec ) p_sys->ki.granule_shift); /* parse all remaining header packets */ - for( i_headeridx = 1; i_headeridx < p_sys->ki.num_headers; ++i_headeridx ) + for( unsigned i_headeridx = 1; i_headeridx < i_count; i_headeridx++ ) { - kp.nbytes = *(p_extra++) << 8; - kp.nbytes |= (*(p_extra++) & 0xFF); - kp.data = p_extra; - p_extra += kp.nbytes; - i_extra -= (kp.nbytes + 2); - if( i_extra < 0 ) - { - msg_Err( p_dec, "header %d data corrupted", i_headeridx ); - return VLC_EGENERIC; - } - + kp.nbytes = pi_size[i_headeridx]; + kp.data = pp_data[i_headeridx]; i_ret = kate_decode_headerin( &p_sys->ki, &p_sys->kc, &kp ); if( i_ret < 0 ) { msg_Err( p_dec, "Kate header %d is corrupted: %d", i_headeridx, i_ret ); - return VLC_EGENERIC; + goto end; } /* header 1 is comments */ @@ -626,14 +574,17 @@ static int ProcessHeaders( decoder_t *p_dec ) else { p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; - p_dec->fmt_out.p_extra = - realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); + p_dec->fmt_out.p_extra = xrealloc( p_dec->fmt_out.p_extra, + p_dec->fmt_out.i_extra ); memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra ); } #endif - return VLC_SUCCESS; +end: + for( unsigned i = 0; i < i_count; i++ ) + free( pp_data[i] ); + return i_ret < 0 ? VLC_EGENERIC : VLC_SUCCESS; } /***************************************************************************** @@ -647,7 +598,7 @@ static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp, subpicture_t *p_buf = NULL; /* Date management */ - if( p_block->i_pts > 0 && p_block->i_pts != p_sys->i_pts ) + if( p_block->i_pts > VLC_TS_INVALID && p_block->i_pts != p_sys->i_pts ) { p_sys->i_pts = p_block->i_pts; } @@ -670,12 +621,10 @@ static subpicture_t *ProcessPacket( decoder_t *p_dec, kate_packet *p_kp, else #endif { - if( p_sys->i_headers >= p_sys->i_num_headers && p_sys->i_num_headers > 0) - p_buf = DecodePacket( p_dec, p_kp, p_block ); - else - p_buf = NULL; + p_buf = DecodePacket( p_dec, p_kp, p_block ); - if( p_block ) block_Release( p_block ); + if( p_block ) + block_Release( p_block ); } return p_buf; @@ -814,28 +763,9 @@ static void SetupText( decoder_t *p_dec, subpicture_t *p_spu, const kate_event * static void TigerDestroySubpicture( subpicture_t *p_subpic ) { - DecSysRelease( p_subpic->p_sys->p_dec_sys ); -} - -static void SubpictureReleaseRegions( subpicture_t *p_subpic ) -{ - if( p_subpic->p_region) - { - subpicture_region_ChainDelete( p_subpic->p_region ); - p_subpic->p_region = NULL; - } -} - -static void TigerPreRender( spu_t *p_spu, subpicture_t *p_subpic, const video_format_t *p_fmt ) -{ - decoder_sys_t *p_sys = p_subpic->p_sys->p_dec_sys; - - VLC_UNUSED( p_spu ); - VLC_UNUSED( p_fmt ); - - p_sys->p_spu_final = p_subpic; + DecSysRelease( p_subpic->updater.p_sys->p_dec_sys ); + free( p_subpic->updater.p_sys ); } - /* * We get premultiplied alpha, but VLC doesn't expect this, so we demultiply * alpha to avoid double multiply (and thus thinner text than we should)). @@ -864,15 +794,15 @@ static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width ) if( a ) { #ifdef WORDS_BIGENDIAN - uint8_t tmp = pixel[2]; - p_pixel[0] = p_pixel[3] * 255 / a; + uint8_t tmp = p_pixel[2]; + p_pixel[0] = clip_uint8_vlc((p_pixel[3] * 255 + a / 2) / a); p_pixel[3] = a; - p_pixel[2] = p_pixel[1] * 255 / a; - p_pixel[1] = tmp * 255 / a; + p_pixel[2] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a); + p_pixel[1] = clip_uint8_vlc((tmp * 255 + a / 2) / a); #else - p_pixel[0] = p_pixel[0] * 255 / a; - p_pixel[1] = p_pixel[1] * 255 / a; - p_pixel[2] = p_pixel[2] * 255 / a; + p_pixel[0] = clip_uint8_vlc((p_pixel[0] * 255 + a / 2) / a); + p_pixel[1] = clip_uint8_vlc((p_pixel[1] * 255 + a / 2) / a); + p_pixel[2] = clip_uint8_vlc((p_pixel[2] * 255 + a / 2) / a); #endif } else @@ -887,82 +817,76 @@ static void PostprocessTigerImage( plane_t *p_plane, unsigned int i_width ) PROFILE_STOP( tiger_renderer_postprocess ); } -/* Tiger renders can end up looking a bit crap since they get overlaid on top of - a subsampled YUV image, so there can be a fair amount of chroma bleeding. - Looks good with white though since it's all luma. Hopefully that will be the - common case. */ -static void TigerUpdateRegions( spu_t *p_spu, subpicture_t *p_subpic, const video_format_t *p_fmt, mtime_t ts ) +static int TigerValidateSubpicture( subpicture_t *p_subpic, + bool b_fmt_src, const video_format_t *p_fmt_src, + bool b_fmt_dst, const video_format_t *p_fmt_dst, + mtime_t ts ) { - decoder_sys_t *p_sys = p_subpic->p_sys->p_dec_sys; - subpicture_region_t *p_r; - video_format_t fmt; - plane_t *p_plane; - kate_float t; - int i_ret; - - VLC_UNUSED( p_spu ); - - PROFILE_START( TigerUpdateRegions ); + decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys; - /* do not render more than once per frame, libtiger renders all events at once */ - if (ts <= p_sys->last_render_ts) - { - SubpictureReleaseRegions( p_subpic ); - return; - } - - /* remember what frame we've rendered already */ - p_sys->last_render_ts = ts; + if( b_fmt_src || b_fmt_dst ) + return VLC_EGENERIC; - if( p_subpic != p_sys->p_spu_final ) - { - SubpictureReleaseRegions( p_subpic ); - return; - } + PROFILE_START( TigerValidateSubpicture ); /* time in seconds from the start of the stream */ - t = (p_subpic->p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f; + kate_float t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f; /* it is likely that the current region (if any) can be kept as is; test for this */ vlc_mutex_lock( &p_sys->lock ); - if( p_subpic->p_region && !p_sys->b_dirty && !tiger_renderer_is_dirty( p_sys->p_tr )) + int i_ret; + if( p_sys->b_dirty || tiger_renderer_is_dirty( p_sys->p_tr ) ) { - PROFILE_START( tiger_renderer_update1 ); - i_ret = tiger_renderer_update( p_sys->p_tr, t, 1 ); - PROFILE_STOP( tiger_renderer_update1 ); - if( i_ret < 0 ) - { - SubpictureReleaseRegions( p_subpic ); - vlc_mutex_unlock( &p_sys->lock ); - return; - } - - if( !tiger_renderer_is_dirty( p_sys->p_tr ) ) - { - /* we can keep the current region list */ - PROFILE_STOP( TigerUpdateRegions ); - vlc_mutex_unlock( &p_sys->lock ); - return; - } + i_ret = VLC_EGENERIC; + goto exit; + } + if( tiger_renderer_update( p_sys->p_tr, t, 1 ) >= 0 && + tiger_renderer_is_dirty( p_sys->p_tr ) ) + { + i_ret = VLC_EGENERIC; + goto exit; } + + i_ret = VLC_SUCCESS; +exit: vlc_mutex_unlock( &p_sys->lock ); + PROFILE_STOP( TigerValidateSubpicture ); + return i_ret; +} - /* we have to render again, reset current region list */ - SubpictureReleaseRegions( p_subpic ); +/* Tiger renders can end up looking a bit crap since they get overlaid on top of + a subsampled YUV image, so there can be a fair amount of chroma bleeding. + Looks good with white though since it's all luma. Hopefully that will be the + common case. */ +static void TigerUpdateSubpicture( subpicture_t *p_subpic, + const video_format_t *p_fmt_src, + const video_format_t *p_fmt_dst, + mtime_t ts ) +{ + decoder_sys_t *p_sys = p_subpic->updater.p_sys->p_dec_sys; + plane_t *p_plane; + kate_float t; + int i_ret; + + + /* time in seconds from the start of the stream */ + t = (p_subpic->updater.p_sys->i_start + ts - p_subpic->i_start ) / 1000000.0f; + + PROFILE_START( TigerUpdateSubpicture ); /* create a full frame region - this will also tell Tiger the size of the frame */ - fmt = *p_fmt; - fmt.i_chroma = VLC_CODEC_RGBA; - fmt.i_width = fmt.i_visible_width; - fmt.i_height = fmt.i_visible_height; + video_format_t fmt = *p_fmt_dst; + fmt.i_chroma = VLC_CODEC_RGBA; fmt.i_bits_per_pixel = 0; - fmt.i_x_offset = fmt.i_y_offset = 0; + fmt.i_width = + fmt.i_visible_width = p_fmt_src->i_width; + fmt.i_height = + fmt.i_visible_height = p_fmt_src->i_height; + fmt.i_x_offset = fmt.i_y_offset = 0; - p_r = subpicture_region_New( &fmt ); + subpicture_region_t *p_r = subpicture_region_New( &fmt ); if( !p_r ) - { return; - } p_r->i_x = 0; p_r->i_y = 0; @@ -997,7 +921,7 @@ static void TigerUpdateRegions( spu_t *p_spu, subpicture_t *p_subpic, const vide p_subpic->p_region = p_r; p_sys->b_dirty = false; - PROFILE_STOP( TigerUpdateRegions ); + PROFILE_STOP( TigerUpdateSubpicture ); vlc_mutex_unlock( &p_sys->lock ); @@ -1250,9 +1174,25 @@ static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t /* we have an event */ /* Get a new spu */ - p_spu = decoder_NewSubpicture( p_dec ); + subpicture_updater_sys_t *p_spu_sys = NULL; + if( p_sys->b_use_tiger) + { + p_spu_sys = malloc( sizeof(*p_spu_sys) ); + if( !p_spu_sys ) + return NULL; + } + subpicture_updater_t updater = { +#ifdef HAVE_TIGER + .pf_validate = TigerValidateSubpicture, + .pf_update = TigerUpdateSubpicture, + .pf_destroy = TigerDestroySubpicture, +#endif + .p_sys = p_spu_sys, + }; + p_spu = decoder_NewSubpicture( p_dec, p_sys->b_use_tiger ? &updater : NULL ); if( !p_spu ) { + free( p_spu_sys ); /* this will happen for lyrics as there is no vout - so no error */ /* msg_Err( p_dec, "Failed to allocate spu buffer" ); */ return NULL; @@ -1266,28 +1206,18 @@ static subpicture_t *DecodePacket( decoder_t *p_dec, kate_packet *p_kp, block_t #ifdef HAVE_TIGER if( p_sys->b_use_tiger) { - /* setup the structure to get our decoder struct back */ - p_spu->p_sys = malloc( sizeof( subpicture_sys_t )); - if( !p_spu->p_sys ) - { - decoder_DeleteSubpicture( p_dec, p_spu ); - return NULL; - } - p_spu->p_sys->p_dec_sys = p_sys; - p_spu->p_sys->i_start = p_block->i_pts; + p_spu_sys->p_dec_sys = p_sys; + p_spu_sys->i_start = p_block->i_pts; DecSysHold( p_sys ); + p_spu->i_stop = __MAX( p_sys->i_max_stop, p_spu->i_stop ); + p_spu->b_ephemer = true; p_spu->b_absolute = true; /* add the event to tiger */ vlc_mutex_lock( &p_sys->lock ); CHECK_TIGER_RET( tiger_renderer_add_event( p_sys->p_tr, ev->ki, ev ) ); vlc_mutex_unlock( &p_sys->lock ); - - /* hookup render/update routines */ - p_spu->pf_pre_render = TigerPreRender; - p_spu->pf_update_regions = TigerUpdateRegions; - p_spu->pf_destroy = TigerDestroySubpicture; } else #endif @@ -1349,7 +1279,6 @@ static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu, /* create a separate region for the bitmap */ memset( &fmt, 0, sizeof(video_format_t) ); fmt.i_chroma = VLC_CODEC_YUVP; - fmt.i_aspect = 0; fmt.i_width = fmt.i_visible_width = ev->bitmap->width; fmt.i_height = fmt.i_visible_height = ev->bitmap->height; fmt.i_x_offset = fmt.i_y_offset = 0; @@ -1372,7 +1301,8 @@ static subpicture_t *SetupSimpleKateSPU( decoder_t *p_dec, subpicture_t *p_spu, /* text region */ fmt.i_chroma = VLC_CODEC_TEXT; - fmt.i_aspect = 0; + fmt.i_sar_num = 0; + fmt.i_sar_den = 1; fmt.i_width = fmt.i_height = 0; fmt.i_x_offset = fmt.i_y_offset = 0; p_spu->p_region = subpicture_region_New( &fmt ); @@ -1499,8 +1429,7 @@ static void DecSysRelease( decoder_sys_t *p_sys ) #ifdef HAVE_TIGER if( p_sys->p_tr ) tiger_renderer_destroy( p_sys->p_tr ); - if( p_sys->psz_tiger_default_font_desc ) - free( p_sys->psz_tiger_default_font_desc ); + free( p_sys->psz_tiger_default_font_desc ); #endif if (p_sys->b_ready)