[vlc-commits] mux: ts: add support for JP2K (#16981)
Francois Cartegnie
git at videolan.org
Tue Jul 25 14:07:43 CEST 2017
vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Sat May 21 20:14:28 2016 +0200| [e89ca61485d0c28db7d8f3be74c31c9ab304def3] | committer: Francois Cartegnie
mux: ts: add support for JP2K (#16981)
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e89ca61485d0c28db7d8f3be74c31c9ab304def3
---
modules/codec/jpeg2000.h | 60 +++++++++++++++++++++++++++++++
modules/mux/Makefile.am | 1 +
modules/mux/mpeg/tables.c | 37 +++++++++++++++++++
modules/mux/mpeg/ts.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 189 insertions(+)
diff --git a/modules/codec/jpeg2000.h b/modules/codec/jpeg2000.h
index 8ea64ecd0b..e2615c4935 100644
--- a/modules/codec/jpeg2000.h
+++ b/modules/codec/jpeg2000.h
@@ -20,6 +20,66 @@
#ifndef VLC_JPEG2000_H
#define VLC_JPEG2000_H
+#define J2K_BOX_JP2C VLC_FOURCC('j','p','2','c')
+
+enum j2k_profiles_e
+{
+ J2K_PROFILE_SD = 0,
+ J2K_PROFILE_HD,
+ J2K_PROFILE_3G,
+ J2K_PROFILE_S3D_HD,
+ J2K_PROFILE_S3D_3G,
+};
+
+static inline bool j2k_is_valid_framerate( unsigned num, unsigned den )
+{
+ const struct
+ {
+ const unsigned num;
+ const unsigned den;
+ } numdens[] = { /* table 2-99 */
+ { 24000, 1001 },
+ { 24, 1 },
+ { 25, 1 },
+ { 30000, 1001 },
+ { 30, 1 },
+ { 50, 1 },
+ { 60000, 1001 },
+ { 60, 1 },
+ };
+ for( size_t i=0; i<ARRAY_SIZE(numdens); i++ )
+ if( numdens[i].den == den && numdens[i].num == num )
+ return true;
+ return false;
+}
+
+static inline enum j2k_profiles_e j2k_get_profile( unsigned w, unsigned h,
+ unsigned num, unsigned den, bool p )
+{
+ const uint64_t s = w * h;
+ const uint64_t f = num / den;
+ if( s <= 720*576 && f < 50 )
+ return J2K_PROFILE_SD; /* VSF_TR-01_2013-04-15 */
+ else if( s <= 1280*720 && f < 60 && p )
+ return J2K_PROFILE_HD;
+ else if( s <= 1920*1080 && f < 60 && !p )
+ return J2K_PROFILE_HD;
+ else
+ return J2K_PROFILE_3G;
+}
+
+static const struct
+{
+ const uint16_t min;
+ const uint16_t max;
+} j2k_profiles_rates[] = {
+ [J2K_PROFILE_SD] = { 25, 200 },
+ [J2K_PROFILE_HD] = { 75, 200 },
+ [J2K_PROFILE_3G] = { 100, 400 },
+ [J2K_PROFILE_S3D_HD] = { 150, 200 },
+ [J2K_PROFILE_S3D_3G] = { 200, 400 },
+};
+
enum j2k_color_specs_e
{
J2K_COLOR_SPEC_UNKNOWN = 0,
diff --git a/modules/mux/Makefile.am b/modules/mux/Makefile.am
index ae26902541..2dd5fcd246 100644
--- a/modules/mux/Makefile.am
+++ b/modules/mux/Makefile.am
@@ -37,6 +37,7 @@ libmux_ts_plugin_la_SOURCES = \
mux/mpeg/streams.h \
mux/mpeg/tables.c mux/mpeg/tables.h \
mux/mpeg/tsutil.c mux/mpeg/tsutil.h \
+ codec/jpeg2000.h \
mux/mpeg/ts.c mux/mpeg/bits.h mux/mpeg/dvbpsi_compat.h
libmux_ts_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) $(DVBPSI_CFLAGS)
libmux_ts_plugin_la_LIBADD = $(DVBPSI_LIBS)
diff --git a/modules/mux/mpeg/tables.c b/modules/mux/mpeg/tables.c
index dd4aa74739..9cab7d7fae 100644
--- a/modules/mux/mpeg/tables.c
+++ b/modules/mux/mpeg/tables.c
@@ -42,6 +42,8 @@
#include "bits.h"
#include "pes.h"
+#include "../../codec/jpeg2000.h"
+
#include <assert.h>
block_t *WritePSISection( dvbpsi_psi_section_t* p_section )
@@ -504,6 +506,34 @@ void BuildPMT( dvbpsi_t *p_dvbpsi, vlc_object_t *p_object,
/* 0xa0 is private */
dvbpsi_pmt_es_descriptor_add( p_es, 0xa0, i_extra + 10, data );
}
+ else if( p_stream->fmt->i_codec == VLC_CODEC_JPEG2000 )
+ {
+ uint8_t *p_data = calloc( 1, 24 + p_stream->fmt->i_extra );
+ if( p_data )
+ {
+ const int profile = j2k_get_profile( p_stream->fmt->video.i_visible_width,
+ p_stream->fmt->video.i_visible_height,
+ p_stream->fmt->video.i_frame_rate,
+ p_stream->fmt->video.i_frame_rate_base, true );
+ p_data[0] = 0x01;
+ if( profile < J2K_PROFILE_HD )
+ p_data[1] = 0x01; /* 0x0101 */
+ else if( profile < J2K_PROFILE_3G )
+ p_data[1] = 0x02; /* 0x0102 */
+ else
+ p_data[1] = 0x04; /* 0x0104 */
+ SetDWBE( &p_data[2], p_stream->fmt->video.i_visible_width );
+ SetDWBE( &p_data[6], p_stream->fmt->video.i_visible_height );
+ SetWBE( &p_data[18], p_stream->fmt->video.i_frame_rate_base );
+ SetWBE( &p_data[20], p_stream->fmt->video.i_frame_rate );
+ p_data[21] = j2k_get_color_spec( p_stream->fmt->video.primaries,
+ p_stream->fmt->video.transfer,
+ p_stream->fmt->video.space );
+ memcpy( &p_data[24], p_stream->fmt->p_extra, p_stream->fmt->i_extra );
+ dvbpsi_pmt_es_descriptor_add( p_es, 0x32, 24 + p_stream->fmt->i_extra, p_data );
+ free(p_data);
+ }
+ }
else if( p_stream->fmt->i_codec == VLC_CODEC_DIRAC )
{
/* Dirac registration descriptor */
@@ -741,6 +771,13 @@ int FillPMTESParams( ts_mux_standard standard, const es_format_t *fmt,
pes->i_stream_id = (PES_EXTENDED_STREAM_ID << 8) | 0x60;
ts->i_stream_type = 0xd1;
break;
+ case VLC_CODEC_JPEG2000:
+ if( !j2k_is_valid_framerate( fmt->video.i_frame_rate,
+ fmt->video.i_frame_rate_base ) )
+ return VLC_EGENERIC;
+ ts->i_stream_type = 0x21;
+ pes->i_stream_id = 0xbd;
+ break;
/* AUDIO */
diff --git a/modules/mux/mpeg/ts.c b/modules/mux/mpeg/ts.c
index a6433c89f2..4a4386a249 100644
--- a/modules/mux/mpeg/ts.c
+++ b/modules/mux/mpeg/ts.c
@@ -62,6 +62,8 @@
#include "tables.h"
+#include "../../codec/jpeg2000.h"
+
/*
* TODO:
* - check PCR frequency requirement
@@ -1111,6 +1113,84 @@ static void SetBlockDuration( sout_input_t *p_input, block_t *p_data )
}
}
+static block_t *Encap_J2K( block_t *p_data, const es_format_t *p_fmt )
+{
+ size_t i_offset = 0;
+ uint32_t i_box = 0;
+ while( p_data->i_buffer > 8 && p_data->i_buffer - i_offset > 8 )
+ {
+ const uint32_t i_size = GetDWBE( &p_data->p_buffer[i_offset] );
+ i_box = VLC_FOURCC( p_data->p_buffer[i_offset + 4],
+ p_data->p_buffer[i_offset + 5],
+ p_data->p_buffer[i_offset + 6],
+ p_data->p_buffer[i_offset + 7] );
+ if( p_data->i_buffer - i_offset < i_size || i_size < 8 )
+ {
+ i_box = 0;
+ break;
+ }
+ else if( i_box == J2K_BOX_JP2C )
+ {
+ break;
+ }
+
+ i_offset += i_size;
+ }
+
+ if( i_box != J2K_BOX_JP2C )
+ {
+ block_Release( p_data );
+ return NULL;
+ }
+
+ if( i_offset < 38 )
+ {
+ block_t *p_realloc = block_Realloc( p_data, 38 - i_offset, p_data->i_buffer );
+ if( unlikely(!p_realloc) )
+ {
+ block_Release( p_data );
+ return NULL;
+ }
+ p_data = p_realloc;
+ }
+ else
+ {
+ p_data->p_buffer += (i_offset - 38);
+ p_data->i_buffer -= (i_offset - 38);
+ }
+
+ const int profile = j2k_get_profile( p_fmt->video.i_visible_width,
+ p_fmt->video.i_visible_height,
+ p_fmt->video.i_frame_rate,
+ p_fmt->video.i_frame_rate_base, true );
+ memcpy( p_data->p_buffer, "elsmfrat", 8 );
+ SetWBE( &p_data->p_buffer[8], p_fmt->video.i_frame_rate_base );
+ SetWBE( &p_data->p_buffer[10], p_fmt->video.i_frame_rate );
+ memcpy( &p_data->p_buffer[12], "brat", 4 );
+ unsigned min = j2k_profiles_rates[profile].min * 1000000;
+ unsigned max = j2k_profiles_rates[profile].max * 1000000;
+ SetDWBE(&p_data->p_buffer[16], max );
+ SetDWBE(&p_data->p_buffer[20], min );
+ memcpy( &p_data->p_buffer[24], "tcod", 4 );
+ const unsigned s = p_data->i_pts / CLOCK_FREQ;
+ const unsigned m = s / 60;
+ const unsigned h = m / 60;
+ const uint64_t l = p_fmt->video.i_frame_rate_base * CLOCK_FREQ /
+ p_fmt->video.i_frame_rate;
+ const unsigned f = (p_data->i_pts % CLOCK_FREQ) / l;
+ p_data->p_buffer[28] = h;
+ p_data->p_buffer[29] = m % 60;
+ p_data->p_buffer[30] = s % 60;
+ p_data->p_buffer[31] = f;
+ memcpy( &p_data->p_buffer[32], "bcol", 4 );
+ p_data->p_buffer[36] = j2k_get_color_spec( p_fmt->video.primaries,
+ p_fmt->video.transfer,
+ p_fmt->video.space );
+ p_data->p_buffer[37] = 0;
+
+ return p_data;
+}
+
/* returns true if needs more data */
static bool MuxStreams(sout_mux_t *p_mux )
{
@@ -1303,6 +1383,17 @@ static bool MuxStreams(sout_mux_t *p_mux )
b_data_alignment = 1;
break;
}
+ else if( p_input->fmt.i_cat == VIDEO_ES )
+ {
+ if( p_input->fmt.i_codec == VLC_CODEC_JPEG2000 )
+ {
+ if( p_data->i_flags & BLOCK_FLAG_INTERLACED_MASK )
+ msg_Warn( p_mux, "Unsupported interlaced J2K content. Expect broken result");
+ p_data = Encap_J2K( p_data, &p_input->fmt );
+ if( !p_data )
+ return false;
+ }
+ }
else if( p_data->i_length < 0 || p_data->i_length > 2000000 )
{
/* FIXME choose a better value, but anyway we
More information about the vlc-commits
mailing list