Commit ba58c3a0 authored by François Cartegnie's avatar François Cartegnie 🤞

codec: add CEA708 decoder

parent c0e99ce5
......@@ -98,7 +98,7 @@ Decoder:
* Support VPX high bit depth support
* Extend MicroDVD support with color, fontname, size, position extensions
* BluRay text subtitles are now decoded
* Improve Closed Captions detection
* Improved Closed Captions detection and optional CEA-708 decoder
Demuxers:
* Support HD-DVD .evo (H.264, VC-1, MPEG-2, PCM, AC-3, E-AC3, MLP, DTS)
......
......@@ -539,8 +539,9 @@
#define VLC_CODEC_EBU_STL VLC_FOURCC('S','T','L',' ')
#define VLC_CODEC_SCTE_18 VLC_FOURCC('S','C','1','8')
#define VLC_CODEC_SCTE_27 VLC_FOURCC('S','C','2','7')
/* EIA/CEA-608 */
/* EIA/CEA-608/708 */
#define VLC_CODEC_CEA608 VLC_FOURCC('c','6','0','8')
#define VLC_CODEC_CEA708 VLC_FOURCC('c','7','0','8')
#define VLC_CODEC_TTML VLC_FOURCC('T','T','M','L')
/* XYZ colorspace 12 bits packed in 16 bits, organisation |XXX0|YYY0|ZZZ0| */
......
......@@ -73,7 +73,7 @@ $Id$
* caf: CAF demuxer
* canvas: Automatically resize and padd a video
* caopengllayer: CoreAnimation OpenGL video output
* cc: CC 608/708 subtitles decoder
* cc: EIA-608/CEA-708 closed captions decoder
* cdda: input module to read audio CDs
* cdg: CD-G decoder
* chain: Video filtering using a chain of video filter modules
......
......@@ -180,7 +180,8 @@ endif
EXTRA_LTLIBRARIES += liblibass_plugin.la
codec_LTLIBRARIES += $(LTLIBlibass)
libcc_plugin_la_SOURCES = codec/cc.c codec/cc.h codec/substext.h
libcc_plugin_la_SOURCES = codec/cc.c codec/cc.h codec/substext.h \
codec/cea708.h codec/cea708.c
codec_LTLIBRARIES += libcc_plugin.la
libcvdsub_plugin_la_SOURCES = codec/cvdsub.c
......
/*****************************************************************************
* cc.c : CC 608/708 subtitles decoder
*****************************************************************************
* Copyright © 2007-2010 Laurent Aimar, 2011 VLC authors and VideoLAN
* Copyright © 2007-2011 Laurent Aimar, VLC authors and VideoLAN
* 2011-2016 VLC authors and VideoLAN
* 2016-2017 VideoLabs, VLC authors and VideoLAN
*
* Authors: Laurent Aimar < fenrir # via.ecp.fr>
*
......@@ -26,11 +28,6 @@
/* The EIA 608 decoder part has been initialy based on ccextractor (GPL)
* and rewritten */
/* TODO:
* Check parity
* 708 decoding
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
......@@ -43,6 +40,7 @@
#include <vlc_charset.h>
#include "substext.h"
#include "cea708.h"
/*****************************************************************************
* Module descriptor.
......@@ -223,13 +221,26 @@ struct decoder_sys_t
int i_reorder_depth;
eia608_t eia608;
cea708_demux_t *p_dtvcc;
cea708_t *p_cea708;
eia608_t *p_eia608;
bool b_opaque;
};
static int Decode( decoder_t *, block_t * );
static void Flush( decoder_t * );
static void DTVCC_ServiceData_Handler( void *priv, uint8_t i_sid, mtime_t i_time,
const uint8_t *p_data, size_t i_data )
{
decoder_t *p_dec = priv;
decoder_sys_t *p_sys = p_dec->p_sys;
//msg_Err( p_dec, "DTVCC_ServiceData_Handler sid %d bytes %ld", i_sid, i_data );
if( i_sid == 1 )
CEA708_Decoder_Push( p_sys->p_cea708, i_time, p_data, i_data );
}
/*****************************************************************************
* Open: probe the decoder and return score
*****************************************************************************
......@@ -241,18 +252,12 @@ static int Open( vlc_object_t *p_this )
decoder_t *p_dec = (decoder_t*)p_this;
decoder_sys_t *p_sys;
if( p_dec->fmt_in.i_codec != VLC_CODEC_CEA608 ||
p_dec->fmt_in.subs.cc.i_channel > 3 )
if( ( p_dec->fmt_in.i_codec != VLC_CODEC_CEA608 ||
p_dec->fmt_in.subs.cc.i_channel > 3 ) &&
( p_dec->fmt_in.i_codec != VLC_CODEC_CEA708 ||
p_dec->fmt_in.subs.cc.i_channel > 63 ) )
return VLC_EGENERIC;
/* 0 -> i_field = 0; i_channel = 1;
1 -> i_field = 0; i_channel = 2;
2 -> i_field = 1; i_channel = 1;
3 -> i_field = 1; i_channel = 2; */
const int i_field = p_dec->fmt_in.subs.cc.i_channel >> 1;
const int i_channel = 1 + (p_dec->fmt_in.subs.cc.i_channel & 1);
p_dec->pf_decode = Decode;
p_dec->pf_flush = Flush;
......@@ -261,11 +266,43 @@ static int Open( vlc_object_t *p_this )
if( p_sys == NULL )
return VLC_ENOMEM;
/* init of p_sys */
p_sys->i_field = i_field;
p_sys->i_channel = i_channel;
if( p_dec->fmt_in.i_codec == VLC_CODEC_CEA608 )
{
/* 0 -> i_field = 0; i_channel = 1;
1 -> i_field = 0; i_channel = 2;
2 -> i_field = 1; i_channel = 1;
3 -> i_field = 1; i_channel = 2; */
p_sys->i_field = p_dec->fmt_in.subs.cc.i_channel >> 1;
p_sys->i_channel = 1 + (p_dec->fmt_in.subs.cc.i_channel & 1);
p_sys->p_eia608 = malloc(sizeof(*p_sys->p_eia608));
if( !p_sys->p_eia608 )
{
free( p_sys );
return VLC_ENOMEM;
}
Eia608Init( p_sys->p_eia608 );
}
else
{
p_sys->p_dtvcc = CEA708_DTVCC_Demuxer_New( p_dec, DTVCC_ServiceData_Handler );
if( !p_sys->p_dtvcc )
{
free( p_sys );
return VLC_ENOMEM;
}
p_sys->p_cea708 = CEA708_Decoder_New( p_dec );
if( !p_sys->p_cea708 )
{
CEA708_DTVCC_Demuxer_Release( p_sys->p_dtvcc );
free( p_sys );
return VLC_ENOMEM;
}
p_sys->i_channel = p_dec->fmt_in.subs.cc.i_channel;
}
Eia608Init( &p_sys->eia608 );
p_sys->b_opaque = var_InheritBool( p_dec, "cc-opaque" );
p_sys->i_reorder_depth = p_dec->fmt_in.subs.cc.i_reorder_depth;
......@@ -281,7 +318,15 @@ static void Flush( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
Eia608Init( &p_sys->eia608 );
if( p_sys->p_eia608 )
{
Eia608Init( p_sys->p_eia608 );
}
else
{
CEA708_DTVCC_Demuxer_Flush( p_sys->p_dtvcc );
CEA708_Decoder_Flush( p_sys->p_cea708 );
}
block_ChainRelease( p_sys->p_queue );
p_sys->p_queue = NULL;
......@@ -320,7 +365,15 @@ static int Decode( decoder_t *p_dec, block_t *p_block )
{
/* Drain */
for( ; DoDecode( p_dec, true ) ; );
Eia608Init( &p_sys->eia608 );
if( p_sys->p_eia608 )
{
Eia608Init( p_sys->p_eia608 );
}
else
{
CEA708_DTVCC_Demuxer_Flush( p_sys->p_dtvcc );
CEA708_Decoder_Flush( p_sys->p_cea708 );
}
if( (p_block->i_flags & BLOCK_FLAG_CORRUPTED) || p_block->i_buffer < 1 )
{
......@@ -359,6 +412,13 @@ static void Close( vlc_object_t *p_this )
decoder_t *p_dec = (decoder_t *)p_this;
decoder_sys_t *p_sys = p_dec->p_sys;
free( p_sys->p_eia608 );
if( p_sys->p_cea708 )
{
CEA708_Decoder_Release( p_sys->p_cea708 );
CEA708_DTVCC_Demuxer_Release( p_sys->p_dtvcc );
}
block_ChainRelease( p_sys->p_queue );
free( p_sys );
}
......@@ -475,29 +535,39 @@ static void Convert( decoder_t *p_dec, mtime_t i_pts,
{
decoder_sys_t *p_sys = p_dec->p_sys;
size_t i_ticks = 0;
unsigned i_ticks = 0;
while( i_buffer >= 3 )
{
/* Mask off the specific i_field bit, else some sequences can be lost. */
if ( (p_buffer[0] & 0x03) == p_sys->i_field &&
(p_buffer[0] & 0x04) /* Valid bit */ )
if( (p_buffer[0] & 0x04) /* Valid bit */ )
{
eia608_status_t i_status =
Eia608Parse( &p_sys->eia608, p_sys->i_channel, &p_buffer[1] );
/* a caption is ready or removed, process its screen */
/*
* In case of rollup/painton with 1 packet/frame, we need to update on Changed status.
* Batch decoding might be incorrect if those in large number of commands (mp4, ...) then.
* see CEAv1.2zero.trp tests
*/
if( i_status & (EIA608_STATUS_DISPLAY | EIA608_STATUS_CHANGED) )
const mtime_t i_spupts = i_pts + i_ticks * CLOCK_FREQ / 30;
/* Mask off the specific i_field bit, else some sequences can be lost. */
if ( p_sys->p_eia608 &&
(p_buffer[0] & 0x03) == p_sys->i_field )
{
subpicture_t *p_spu = Subtitle( p_dec, &p_sys->eia608, i_pts + i_ticks * CLOCK_FREQ / 30 );
if( p_spu )
decoder_QueueSub( p_dec, p_spu );
eia608_status_t i_status = Eia608Parse( p_sys->p_eia608,
p_sys->i_channel, &p_buffer[1] );
/* a caption is ready or removed, process its screen */
/*
* In case of rollup/painton with 1 packet/frame, we need
* to update on Changed status.
* Batch decoding might be incorrect if those in
* large number of commands (mp4, ...) then.
* see CEAv1.2zero.trp tests */
if( i_status & (EIA608_STATUS_DISPLAY | EIA608_STATUS_CHANGED) )
{
subpicture_t *p_spu = Subtitle( p_dec, p_sys->p_eia608, i_spupts );
if( p_spu )
decoder_QueueSub( p_dec, p_spu );
}
}
else if( p_sys->p_cea708 && (p_buffer[0] & 0x03) >= 2 )
{
CEA708_DTVCC_Demuxer_Push( p_sys->p_dtvcc, i_spupts, p_buffer );
}
}
i_ticks++;
i_buffer -= 3;
......
This diff is collapsed.
/*****************************************************************************
* cea708.h : CEA708 subtitles decoder
*****************************************************************************
* Copyright © 2017 Videolabs, VideoLAN and VLC authors
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
#ifndef VLC_CEA708_H_
#define VLC_CEA708_H_
typedef void(*service_data_hdlr_t)(void *, uint8_t i_sid, mtime_t,
const uint8_t *p_data, size_t i_data);
/* DVTCC Services demuxing */
#define CEA708_DTVCC_MAX_PKT_SIZE 128
typedef struct cea708_demux_t cea708_demux_t;
cea708_demux_t * CEA708_DTVCC_Demuxer_New( void *, service_data_hdlr_t );
void CEA708_DTVCC_Demuxer_Release( cea708_demux_t * );
void CEA708_DTVCC_Demuxer_Push( cea708_demux_t *h, mtime_t, const uint8_t data[3] );
void CEA708_DTVCC_Demuxer_Flush( cea708_demux_t *h );
/* DVTCC Services decoding */
typedef struct cea708_t cea708_t;
cea708_t *CEA708_Decoder_New( decoder_t * );
void CEA708_Decoder_Release( cea708_t *p_cea708 );
void CEA708_Decoder_Push( cea708_t *p_cea708, mtime_t,
const uint8_t *p_data, size_t i_data );
void CEA708_Decoder_Flush( cea708_t *p_cea708 );
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment