1 /*****************************************************************************
2 * mjpeg.c: MPEG packetizer
3 *****************************************************************************
4 * Copyright (C) 2018 VideoLabs, VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
21 /*****************************************************************************
23 *****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_block.h>
32 #include <vlc_codec.h>
33 #include <vlc_block_helper.h>
34 #include "packetizer_helper.h"
36 /*****************************************************************************
38 *****************************************************************************/
41 packetizer_t packetizer
;
42 int i_next_block_flags
;
46 static const uint8_t p_mjpg_startcode
[4] = { 0xFF, 0xD8, 0xFF, 0xE0 };
48 static inline const uint8_t * startcode_Find( const uint8_t *p
, const uint8_t *end
)
52 p
= memchr( p
, 0xFF, end
- p
);
53 if( !p
|| end
- p
< 4 )
55 if( p
[1] == 0xD8 && p
[2] == 0xFF && (p
[3] & 0xE0) == 0xE0 )
62 /*****************************************************************************
64 *****************************************************************************/
65 static block_t
*Packetize( decoder_t
*p_dec
, block_t
**pp_block
)
67 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
68 return packetizer_Packetize( &p_sys
->packetizer
, pp_block
);
71 static void PacketizeFlush( decoder_t
*p_dec
)
73 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
75 date_Set( &p_sys
->date
, VLC_TICK_INVALID
);
76 p_sys
->i_next_block_flags
= BLOCK_FLAG_DISCONTINUITY
;
77 packetizer_Flush( &p_sys
->packetizer
);
80 /*****************************************************************************
82 *****************************************************************************/
83 static void PacketizeReset( void *p_private
, bool b_flush
)
86 decoder_t
*p_dec
= p_private
;
87 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
89 date_Set( &p_sys
->date
, VLC_TICK_INVALID
);
90 p_sys
->i_next_block_flags
= BLOCK_FLAG_DISCONTINUITY
;
93 static block_t
*PacketizeParse( void *p_private
, bool *pb_ts_used
, block_t
*p_block
)
95 decoder_t
*p_dec
= p_private
;
96 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
98 const uint8_t *p_buf
= &p_block
->p_buffer
[2];
99 size_t i_buf
= p_block
->i_buffer
- 2;
101 while( i_buf
> 4 && p_buf
[0] == 0xFF )
103 size_t i_size
= 2 + GetWBE( &p_buf
[2] );
106 if( p_buf
[1] == 0xC0 && i_buf
> 9 )
108 uint16_t i_height
= GetWBE( &p_buf
[5] );
109 uint16_t i_width
= GetWBE( &p_buf
[7] );
110 if( i_height
&& i_width
&&
111 (p_dec
->fmt_out
.video
.i_height
!= i_height
||
112 p_dec
->fmt_out
.video
.i_width
!= i_width
) )
114 p_dec
->fmt_out
.video
.i_width
=
115 p_dec
->fmt_out
.video
.i_visible_width
= i_width
;
116 p_dec
->fmt_out
.video
.i_height
=
117 p_dec
->fmt_out
.video
.i_visible_height
= i_height
;
125 if( p_block
->i_dts
== VLC_TICK_INVALID
)
126 p_block
->i_dts
= p_block
->i_pts
;
127 else if( p_block
->i_pts
== VLC_TICK_INVALID
)
128 p_block
->i_pts
= p_block
->i_dts
;
130 vlc_tick_t i_prev_dts
= date_Get( &p_sys
->date
);
131 if( p_block
->i_dts
!= VLC_TICK_INVALID
)
133 date_Set( &p_sys
->date
, p_block
->i_dts
);
135 else if( p_dec
->fmt_in
.video
.i_frame_rate
&&
136 p_dec
->fmt_in
.video
.i_frame_rate_base
)
138 date_Increment( &p_sys
->date
, 1 );
139 p_block
->i_dts
= p_block
->i_pts
= date_Get( &p_sys
->date
);
142 if( i_prev_dts
!= VLC_TICK_INVALID
&& p_block
->i_dts
!= VLC_TICK_INVALID
)
143 p_block
->i_length
= p_block
->i_dts
- i_prev_dts
;
147 p_block
->i_flags
= p_sys
->i_next_block_flags
| BLOCK_FLAG_TYPE_I
;
148 p_sys
->i_next_block_flags
= 0;
153 static int PacketizeValidate( void *p_private
, block_t
*p_au
)
155 VLC_UNUSED(p_private
);
160 /*****************************************************************************
162 *****************************************************************************/
163 static void Close( vlc_object_t
*p_this
)
165 decoder_t
*p_dec
= (decoder_t
*)p_this
;
166 decoder_sys_t
*p_sys
= p_dec
->p_sys
;
168 packetizer_Clean( &p_sys
->packetizer
);
173 /*****************************************************************************
175 *****************************************************************************/
176 static int Open( vlc_object_t
*p_this
)
178 decoder_t
*p_dec
= (decoder_t
*)p_this
;
179 decoder_sys_t
*p_sys
;
181 if( p_dec
->fmt_in
.i_codec
!= VLC_CODEC_MJPG
)
184 p_dec
->p_sys
= p_sys
= malloc( sizeof( decoder_sys_t
) );
188 p_sys
->i_next_block_flags
= 0;
190 if( p_dec
->fmt_in
.video
.i_frame_rate
&&
191 p_dec
->fmt_in
.video
.i_frame_rate_base
)
193 date_Init( &p_sys
->date
, p_dec
->fmt_in
.video
.i_frame_rate
,
194 p_dec
->fmt_in
.video
.i_frame_rate_base
);
197 date_Init( &p_sys
->date
, 30000, 1001 );
199 es_format_Copy( &p_dec
->fmt_out
, &p_dec
->fmt_in
);
202 packetizer_Init( &p_sys
->packetizer
,
203 p_mjpg_startcode
, sizeof(p_mjpg_startcode
), startcode_Find
,
205 PacketizeReset
, PacketizeParse
, PacketizeValidate
, NULL
,
208 p_dec
->pf_packetize
= Packetize
;
209 p_dec
->pf_flush
= PacketizeFlush
;
210 p_dec
->pf_get_cc
= NULL
;
215 /*****************************************************************************
217 *****************************************************************************/
220 set_category( CAT_SOUT
)
221 set_subcategory( SUBCAT_SOUT_PACKETIZER
)
222 set_description( N_("MJPEG video packetizer") )
223 set_capability( "packetizer", 50 )
224 set_callbacks( Open
, Close
)