[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