packetizer: avparser: properly propagate flags
[vlc.git] / modules / packetizer / avparser.c
blob613e657993067bf3269d4ea6a74ec043be7c743b
1 /*****************************************************************************
2 * avparser.c
3 *****************************************************************************
4 * Copyright (C) 2015 VLC authors and VideoLAN
6 * Authors: Denis Charmet <typx@videolan.org>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
23 /*****************************************************************************
24 * Preamble
25 *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33 #include <vlc_codec.h>
34 #include <vlc_block.h>
36 #include "../codec/avcodec/avcodec.h"
37 #include "../codec/avcodec/avcommon.h"
39 #include "avparser.h"
40 /*****************************************************************************
41 * Module descriptor
42 *****************************************************************************/
43 #ifndef MERGE_FFMPEG
44 vlc_module_begin ()
45 AVPARSER_MODULE
46 vlc_module_end ()
47 #endif
49 /*****************************************************************************
50 * Local prototypes
51 *****************************************************************************/
52 typedef struct
54 AVCodecParserContext * p_parser_ctx;
55 AVCodecContext * p_codec_ctx;
56 int i_offset;
57 } decoder_sys_t;
59 static block_t * Packetize( decoder_t *, block_t ** );
60 static block_t * PacketizeClosed( decoder_t *, block_t ** );
62 /*****************************************************************************
63 * FlushPacketizer: reopen as there's no clean way to flush avparser
64 *****************************************************************************/
65 static void FlushPacketizer( decoder_t *p_dec )
67 avparser_ClosePacketizer( VLC_OBJECT( p_dec ) );
68 p_dec->p_sys = NULL;
69 int res = avparser_OpenPacketizer( VLC_OBJECT( p_dec ) );
70 if ( res != VLC_SUCCESS )
72 msg_Err( p_dec, "failed to flush with error %d", res );
73 p_dec->pf_packetize = PacketizeClosed;
77 /*****************************************************************************
78 * avparser_OpenPacketizer: probe the packetizer and return score
79 *****************************************************************************
80 * Tries to launch a decoder and return score so that the interface is able
81 * to choose.
82 *****************************************************************************/
83 int avparser_OpenPacketizer( vlc_object_t *p_this )
85 decoder_t *p_dec = (decoder_t*)p_this;
86 decoder_sys_t *p_sys;
88 /* Restrict to VP9 for now */
89 if( p_dec->fmt_in.i_codec != VLC_CODEC_VP9 )
90 return VLC_EGENERIC;
92 unsigned i_avcodec_id;
94 if( !GetFfmpegCodec( p_dec->fmt_in.i_cat, p_dec->fmt_in.i_codec,
95 &i_avcodec_id, NULL ) )
96 return VLC_EGENERIC;
98 /* init avcodec */
99 vlc_init_avcodec(p_this);
101 /* It is less likely to have a parser than a codec, start by that */
102 AVCodecParserContext * p_ctx = av_parser_init( i_avcodec_id );
103 if( !p_ctx )
104 return VLC_EGENERIC;
106 AVCodec * p_codec = avcodec_find_decoder( i_avcodec_id );
107 if( unlikely( !p_codec ) )
109 av_parser_close( p_ctx );
110 return VLC_EGENERIC;
113 AVCodecContext * p_codec_ctx = avcodec_alloc_context3( p_codec );
114 if( unlikely( !p_codec_ctx ) )
116 av_parser_close( p_ctx );
117 return VLC_ENOMEM;
120 p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) );
122 if( unlikely( !p_sys ) )
124 avcodec_free_context( &p_codec_ctx );
125 av_parser_close( p_ctx );
126 return VLC_ENOMEM;
128 p_dec->pf_packetize = Packetize;
129 p_dec->pf_flush = FlushPacketizer;
130 p_dec->pf_get_cc = NULL;
131 p_sys->p_parser_ctx = p_ctx;
132 p_sys->p_codec_ctx = p_codec_ctx;
133 p_sys->i_offset = 0;
134 es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
136 return VLC_SUCCESS;
139 /*****************************************************************************
140 * avparser_ClosePacketizer:
141 *****************************************************************************/
142 void avparser_ClosePacketizer( vlc_object_t *p_this )
144 decoder_t *p_dec = (decoder_t*)p_this;
145 decoder_sys_t *p_sys = p_dec->p_sys;
146 if (likely( p_sys != NULL ))
148 avcodec_free_context( &p_sys->p_codec_ctx );
149 av_parser_close( p_sys->p_parser_ctx );
150 free( p_sys );
154 /*****************************************************************************
155 * Packetize: packetize a frame
156 *****************************************************************************/
157 static block_t *Packetize ( decoder_t *p_dec, block_t **pp_block )
159 decoder_sys_t *p_sys = p_dec->p_sys;
161 if( pp_block == NULL || *pp_block == NULL )
162 return NULL;
163 if( (*pp_block)->i_flags&(BLOCK_FLAG_CORRUPTED) )
165 block_Release( *pp_block );
166 return NULL;
169 block_t * p_block = *pp_block;
171 uint8_t * p_indata = p_block->p_buffer + p_sys->i_offset;
172 int i_inlen = p_block->i_buffer - p_sys->i_offset;
173 uint8_t * p_outdata;
174 int i_outlen;
176 if( p_sys->i_offset == i_inlen )
177 goto out;
179 p_sys->i_offset += av_parser_parse2( p_sys->p_parser_ctx, p_sys->p_codec_ctx,
180 &p_outdata, &i_outlen, p_indata, i_inlen,
181 TO_AV_TS(p_block->i_pts), TO_AV_TS(p_block->i_dts), -1);
183 if( unlikely( i_outlen <= 0 || !p_outdata ) )
184 goto out;
186 block_t * p_ret = block_Alloc( i_outlen );
188 if( unlikely ( !p_ret ) )
189 goto out;
191 p_ret->i_flags = p_block->i_flags;
193 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
194 p_block->i_flags &= ~BLOCK_FLAG_DISCONTINUITY;
196 memcpy( p_ret->p_buffer, p_outdata, i_outlen );
197 p_ret->i_pts = p_block->i_pts;
198 p_ret->i_dts = p_block->i_dts;
199 if( p_sys->p_parser_ctx->key_frame == 1 )
200 p_ret->i_flags |= BLOCK_FLAG_TYPE_I;
202 p_block->i_pts = p_block->i_dts = VLC_TICK_INVALID;
204 return p_ret;
206 out:
207 p_sys->i_offset = 0;
208 block_Release( *pp_block );
209 *pp_block = NULL;
210 return NULL;
213 /*****************************************************************************
214 * PacketizeClosed: packetizer called after a flush failed
215 *****************************************************************************/
216 static block_t *PacketizeClosed ( decoder_t *p_dec, block_t **pp_block )
218 (void) p_dec;
219 if( pp_block != NULL && *pp_block != NULL )
220 block_Release( *pp_block );
221 return NULL;