]> git.sesse.net Git - vlc/blob - modules/packetizer/avparser.c
decoder: factor some common code into DecoderUpdateFormatLocked()
[vlc] / modules / packetizer / avparser.c
1 /*****************************************************************************
2  * avparser.c
3  *****************************************************************************
4  * Copyright (C) 2015 VLC authors and VideoLAN
5  * $Id$
6  *
7  * Authors: Denis Charmet <typx@videolan.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_codec.h>
35 #include <vlc_block.h>
36
37 #include "../codec/avcodec/avcodec.h"
38 #include "../codec/avcodec/avcommon.h"
39
40 #include "avparser.h"
41 /*****************************************************************************
42  * Module descriptor
43  *****************************************************************************/
44 #ifndef MERGE_FFMPEG
45 vlc_module_begin ()
46     AVPARSER_MODULE
47 vlc_module_end ()
48 #endif
49
50 /*****************************************************************************
51  * Local prototypes
52  *****************************************************************************/
53 struct decoder_sys_t
54 {
55     AVCodecParserContext * p_parser_ctx;
56     AVCodecContext * p_codec_ctx;
57     int i_offset;
58 };
59
60 static block_t * Packetize( decoder_t *, block_t ** );
61
62 /*****************************************************************************
63  * OpenPacketizer: probe the packetizer and return score
64  *****************************************************************************
65  * Tries to launch a decoder and return score so that the interface is able
66  * to choose.
67  *****************************************************************************/
68 int OpenPacketizer( vlc_object_t *p_this )
69 {
70     decoder_t     *p_dec = (decoder_t*)p_this;
71     decoder_sys_t *p_sys;
72
73     /* Restrict to VP9 for now */
74     if( p_dec->fmt_in.i_codec != VLC_CODEC_VP9 )
75         return VLC_EGENERIC;
76
77     unsigned i_avcodec_id;
78
79     if( !GetFfmpegCodec( p_dec->fmt_in.i_codec, NULL, &i_avcodec_id, NULL ) )
80         return VLC_EGENERIC;
81
82     /* init avcodec */
83     vlc_init_avcodec(p_this);
84
85     /* It is less likely to have a parser than a codec, start by that */
86     AVCodecParserContext * p_ctx = av_parser_init( i_avcodec_id );
87     if( !p_ctx )
88         return VLC_EGENERIC;
89
90     AVCodec * p_codec = avcodec_find_decoder( i_avcodec_id );
91     if( unlikely( !p_codec ) )
92     {
93         av_parser_close( p_ctx );
94         return VLC_EGENERIC;
95     }
96
97     AVCodecContext * p_codec_ctx = avcodec_alloc_context3( p_codec );
98     if( unlikely( !p_codec_ctx ) )
99     {
100         av_parser_close( p_ctx );
101         return VLC_ENOMEM;
102     }
103
104     p_dec->p_sys = p_sys = malloc( sizeof(*p_sys) );
105
106     if( unlikely( !p_sys ) )
107     {
108         avcodec_free_context( &p_codec_ctx );
109         av_parser_close( p_ctx );
110         return VLC_ENOMEM;
111     }
112     p_dec->pf_packetize = Packetize;
113     p_sys->p_parser_ctx = p_ctx;
114     p_sys->p_codec_ctx = p_codec_ctx;
115     p_sys->i_offset = 0;
116     es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
117
118     return VLC_SUCCESS;
119 }
120
121 /*****************************************************************************
122  * ClosePacketizer:
123  *****************************************************************************/
124 void ClosePacketizer( vlc_object_t *p_this )
125 {
126     decoder_t     *p_dec = (decoder_t*)p_this;
127     avcodec_free_context( &p_dec->p_sys->p_codec_ctx );
128     av_parser_close( p_dec->p_sys->p_parser_ctx );
129     es_format_Clean( &p_dec->fmt_out );
130     free( p_dec->p_sys );
131 }
132
133 /*****************************************************************************
134  * Packetize: packetize a frame
135  *****************************************************************************/
136 static block_t *Packetize ( decoder_t *p_dec, block_t **pp_block )
137 {
138     decoder_sys_t *p_sys = p_dec->p_sys;
139
140     if( pp_block == NULL || *pp_block == NULL )
141         return NULL;
142     if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) )
143     {
144         block_Release( *pp_block );
145         return NULL;
146     }
147
148     block_t * p_block = *pp_block;
149
150     uint8_t * p_indata = p_block->p_buffer + p_sys->i_offset;
151     int i_inlen = p_block->i_buffer -  p_sys->i_offset;
152     uint8_t * p_outdata;
153     int i_outlen;
154
155     if( p_sys->i_offset == i_inlen )
156         goto out;
157
158     p_sys->i_offset += av_parser_parse2( p_sys->p_parser_ctx, p_sys->p_codec_ctx,
159                                          &p_outdata, &i_outlen, p_indata, i_inlen,
160                                          p_block->i_pts, p_block->i_dts, -1);
161
162     if( unlikely( i_outlen <= 0 || !p_outdata ) )
163         goto out;
164
165     block_t * p_ret = block_Alloc( i_outlen );
166
167     if( unlikely ( !p_ret ) )
168         goto out;
169
170     memcpy( p_ret->p_buffer, p_outdata, i_outlen );
171     p_ret->i_pts = p_block->i_pts;
172     p_ret->i_dts = p_block->i_dts;
173
174     p_block->i_pts = p_block->i_dts = VLC_TS_INVALID;
175
176     return p_ret;
177
178 out:
179     p_sys->i_offset = 0;
180     block_Release( *pp_block );
181     *pp_block = NULL;
182     return NULL;
183 }
184