Commit 36f547ec authored by François Cartegnie's avatar François Cartegnie 🤞

codecs: add SCTE-18 decoder

parent 164ef9f2
......@@ -500,6 +500,7 @@
#define VLC_CODEC_BD_PG VLC_FOURCC('b','d','p','g')
/* EBU STL (TECH. 3264-E) */
#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-608 */
#define VLC_CODEC_EIA608_1 VLC_FOURCC('c','c','1',' ')
......
......@@ -330,6 +330,7 @@ $Id$
* scene: scene video filter
* schroedinger: Schroedinger video decoder
* screen: a input module that takes screenshots of the primary monitor
* scte18: SCTE-18/Emergency Alert Messaging for Cable decoder
* scte27: SCTE-27/Digicipher subtitles decoder
* sd_journal: logger output to SystemD journal
* sdl_image: SDL-based image decoder
......
......@@ -182,6 +182,10 @@ libaribsub_plugin_la_LIBADD = $(ARIBB24_LIBS)
EXTRA_LTLIBRARIES += libaribsub_plugin.la
codec_LTLIBRARIES += $(LTLIBaribsub)
libscte18_plugin_la_SOURCES = codec/scte18.c codec/scte18.h \
codec/atsc_a65.c codec/atsc_a65.h
codec_LTLIBRARIES += libscte18_plugin.la
libscte27_plugin_la_SOURCES = codec/scte27.c
codec_LTLIBRARIES += libscte27_plugin.la
......
/*****************************************************************************
* scte18.c : SCTE-18 EAS decoder
*****************************************************************************
* Copyright (C) 2016 - VideoLAN 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_codec.h>
#include "atsc_a65.h"
#include "scte18.h"
#include "substext.h"
#include <time.h>
/*****************************************************************************
* Module descriptor.
*****************************************************************************/
static int Open (vlc_object_t *);
static void Close(vlc_object_t *);
vlc_module_begin ()
set_description(N_("SCTE-18 decoder"))
set_shortname(N_("SCTE-18"))
set_capability( "decoder", 51)
set_category(CAT_INPUT)
set_subcategory(SUBCAT_INPUT_SCODEC)
set_callbacks(Open, Close)
vlc_module_end ()
struct decoder_sys_t
{
atsc_a65_handle_t *p_handle;
};
//#define GPS_UTC_EPOCH_OFFSET 315964800
//#define GPS_CUR_UTC_LEAP_OFFSET 16 /* 1 Jul 2015 */
typedef struct scte18_cea_t
{
uint16_t i_eas_event_id;
char rgc_eas_originator_code[3];
char * psz_eas_event_code;
char * psz_nature_of_activation;
uint8_t alert_message_time_remaining;
uint32_t event_start_time;
uint16_t event_duration;
uint8_t alert_priority;
char * psz_alert_text;
} scte18_cea_t;
/****************************************************************************
* Local prototypes
****************************************************************************/
#define BUF_ADVANCE(n) p_buffer += n; i_buffer -= n;
static inline scte18_cea_t * scte18_cea_New()
{
return calloc( 1, sizeof(scte18_cea_t) );
}
static void scte18_cea_Free( scte18_cea_t *p_cea )
{
free( p_cea->psz_alert_text );
free( p_cea->psz_nature_of_activation );
free( p_cea->psz_eas_event_code );
free( p_cea );
}
static scte18_cea_t * scte18_cea_Decode( atsc_a65_handle_t *p_handle, const block_t *p_block )
{
size_t len;
scte18_cea_t *p_cea = scte18_cea_New();
if( !p_cea )
return NULL;
const uint8_t *p_buffer = p_block->p_buffer;
size_t i_buffer = p_block->i_buffer;
if( i_buffer < 34 || p_buffer[0] != 0 )
goto error;
BUF_ADVANCE(1);
p_cea->i_eas_event_id = GetWBE( p_buffer );
BUF_ADVANCE(2);
memcpy( p_cea->rgc_eas_originator_code, p_buffer, 3 );
BUF_ADVANCE(3);
len = p_buffer[0];
if( i_buffer < 23 + len )
goto error;
p_cea->psz_eas_event_code = malloc( len + 1 );
memcpy( p_cea->psz_eas_event_code, &p_buffer[1], len );
p_cea->psz_eas_event_code[len] = 0;
BUF_ADVANCE( len + 1 );
len = p_buffer[0];
if( i_buffer < len + 22 )
goto error;
p_cea->psz_nature_of_activation = atsc_a65_Decode_multiple_string( p_handle, &p_buffer[1], len );
BUF_ADVANCE(1 + len);
if( i_buffer < 21 )
goto error;
p_cea->alert_message_time_remaining = p_buffer[0];
BUF_ADVANCE(1);
p_cea->event_start_time = GetDWBE( p_buffer );
BUF_ADVANCE(4);
p_cea->event_duration = GetWBE( p_buffer );
if( p_cea->event_duration != 0 && ( p_cea->event_duration < 15 || p_cea->event_duration > 6000 ) )
goto error;
BUF_ADVANCE(2);
p_cea->alert_priority = p_buffer[1] & 0x0f;
switch( p_cea->alert_priority )
{
case EAS_PRIORITY_TEST:
case EAS_PRIORITY_LOW:
case EAS_PRIORITY_MEDIUM:
case EAS_PRIORITY_HIGH:
case EAS_PRIORITY_MAX:
break;
default:
goto error;
}
BUF_ADVANCE(2);
BUF_ADVANCE(2); //OOB_ID
BUF_ADVANCE(2); //
BUF_ADVANCE(2); //
BUF_ADVANCE(2); //audio_OOB_ID
len = GetWBE( p_buffer );
if( i_buffer < len + 2 )
goto error;
p_cea->psz_alert_text = atsc_a65_Decode_multiple_string( p_handle, &p_buffer[2], len );
return p_cea;
error:
scte18_cea_Free( p_cea );
return NULL;
}
static subpicture_t *Decode( decoder_t *p_dec, block_t **pp_block )
{
if ( pp_block == NULL || *pp_block == NULL )
return NULL;
block_t *p_block = *pp_block; *pp_block = NULL;
subpicture_t *p_spu = NULL;
if (p_block->i_flags & (BLOCK_FLAG_CORRUPTED))
goto exit;
scte18_cea_t *p_cea = scte18_cea_Decode( p_dec->p_sys->p_handle, p_block );
if( p_cea )
{
p_spu = decoder_NewSubpictureText( p_dec );
if( p_spu )
{
subpicture_updater_sys_t *p_spu_sys = p_spu->updater.p_sys;
p_spu->i_start = p_block->i_pts;
if( p_cea->alert_message_time_remaining )
p_spu->i_stop = p_spu->i_start + CLOCK_FREQ * p_cea->alert_message_time_remaining;
else
p_spu->i_stop = VLC_TS_INVALID;
p_spu->b_ephemer = true;
p_spu->b_absolute = false;
p_spu_sys->align = SUBPICTURE_ALIGN_TOP;
p_spu_sys->p_default_style->i_style_flags = STYLE_BOLD | STYLE_BACKGROUND;
p_spu_sys->p_default_style->i_features |= STYLE_HAS_FLAGS;
p_spu_sys->p_default_style->i_background_color = 0x000000;
p_spu_sys->p_default_style->i_background_alpha = STYLE_ALPHA_OPAQUE;
p_spu_sys->p_default_style->i_features |= STYLE_HAS_BACKGROUND_COLOR | STYLE_HAS_BACKGROUND_ALPHA;
p_spu_sys->p_default_style->i_font_color = 0xFF0000;
p_spu_sys->p_default_style->i_features |= STYLE_HAS_FONT_COLOR;
p_spu_sys->p_segments = text_segment_New( p_cea->psz_alert_text );
}
msg_Info( p_dec, "Received %s", p_cea->psz_alert_text );
scte18_cea_Free( p_cea );
}
exit:
block_Release( p_block );
return p_spu;
}
static int Open( vlc_object_t *object )
{
decoder_t *dec = (decoder_t *)object;
if ( dec->fmt_in.i_codec != VLC_CODEC_SCTE_18 )
return VLC_EGENERIC;
decoder_sys_t *p_sys = malloc( sizeof(decoder_sys_t) );
if( unlikely(!p_sys) )
return VLC_ENOMEM;
p_sys->p_handle = atsc_a65_handle_New( NULL );
if( !p_sys->p_handle )
{
free( p_sys );
return VLC_EGENERIC;
}
dec->p_sys = p_sys;
dec->pf_decode_sub = Decode;
es_format_Init( &dec->fmt_out, SPU_ES, 0 );
return VLC_SUCCESS;
}
static void Close( vlc_object_t *p_object )
{
decoder_t *p_dec = (decoder_t *)p_object;
decoder_sys_t *p_sys = (decoder_sys_t *) p_dec->p_sys;
atsc_a65_handle_Release( p_sys->p_handle );
free( p_sys );
}
/*****************************************************************************
* scte18.h : SCTE-18 EAS decoder
*****************************************************************************
* Copyright (C) 2016 - VideoLAN 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 General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifndef VLC_SCTE18_H
#define VLC_SCTE18_H
#define SCTE18_SI_BASE_PID 0x1FFB
#define SCTE18_TABLE_ID 0xD8
#define SCTE18_DESCRIPTION N_("Emergency Alert Messaging for Cable")
enum
{
EAS_PRIORITY_TEST = 0,
EAS_PRIORITY_LOW = 3,
EAS_PRIORITY_MEDIUM = 7,
EAS_PRIORITY_HIGH = 11,
EAS_PRIORITY_MAX = 15
};
/* Get priority without decoding
*/
static inline int scte18_get_EAS_priority( const uint8_t *p_buffer, size_t i_buffer )
{
if( i_buffer < 17 || p_buffer[0] )
return -1;
size_t i_offset = 6;
size_t i_len = p_buffer[i_offset]; /* EAS code Len */
i_offset += i_len + 1; /* EAS code Text */
if( i_offset >= i_buffer )
return -1;
i_len = p_buffer[i_offset]; /* NOA Len */
i_offset += i_len + 1; /* NOA Text */
i_offset += 1 + 4 + 2 + 1;
if( i_offset >= i_buffer )
return -1;
return (p_buffer[i_offset] & 0x0f);
}
#endif
......@@ -394,6 +394,8 @@ modules/codec/quicktime.c
modules/codec/rawvideo.c
modules/codec/rtpvideo.c
modules/codec/schroedinger.c
modules/codec/scte18.c
modules/codec/scte18.h
modules/codec/sdl_image.c
modules/codec/shine.c
modules/codec/speex.c
......
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