2 * This file is part of FFmpeg.
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include "libavutil/opt.h"
21 #include "libavcodec/apv.h"
22 #include "libavcodec/bytestream.h"
25 #include "avio_internal.h"
29 typedef struct APVDemuxerContext
{
30 const AVClass
*class; /**< Class for private options. */
31 AVRational framerate
; /**< AVRational describing framerate, set by a private option. */
34 typedef struct APVHeaderInfo
{
45 uint8_t bit_depth_minus8
;
48 static int apv_extract_header_info(GetByteContext
*gbc
)
50 APVHeaderInfo header
, *info
= &header
;
53 info
->pbu_type
= bytestream2_get_byte(gbc
);
54 info
->group_id
= bytestream2_get_be16(gbc
);
56 zero
= bytestream2_get_byte(gbc
);
58 return AVERROR_INVALIDDATA
;
60 if (info
->pbu_type
== APV_PBU_ACCESS_UNIT_INFORMATION
) {
61 unsigned int num_frames
= bytestream2_get_be16(gbc
);
64 return AVERROR_INVALIDDATA
;
66 info
->pbu_type
= bytestream2_get_byte(gbc
);
67 if (info
->pbu_type
!= APV_PBU_PRIMARY_FRAME
&&
68 info
->pbu_type
!= APV_PBU_NON_PRIMARY_FRAME
&&
69 (info
->pbu_type
< APV_PBU_PREVIEW_FRAME
|| info
->pbu_type
> APV_PBU_ALPHA_FRAME
))
70 return AVERROR_INVALIDDATA
;
72 bytestream2_skip(gbc
, 2); // group_id
73 zero
= bytestream2_get_byte(gbc
);
75 return AVERROR_INVALIDDATA
;
76 } else if (info
->pbu_type
!= APV_PBU_PRIMARY_FRAME
)
77 return AVERROR_INVALIDDATA
;
79 info
->profile_idc
= bytestream2_get_byte(gbc
);
80 info
->level_idc
= bytestream2_get_byte(gbc
);
82 byte
= bytestream2_get_byte(gbc
);
83 info
->band_idc
= byte
>> 3;
86 return AVERROR_INVALIDDATA
;
88 info
->frame_width
= bytestream2_get_be24(gbc
);
89 info
->frame_height
= bytestream2_get_be24(gbc
);
90 if (info
->frame_width
< 1 || info
->frame_width
> 65536 ||
91 info
->frame_height
< 1 || info
->frame_height
> 65536)
92 return AVERROR_INVALIDDATA
;
94 byte
= bytestream2_get_byte(gbc
);
95 info
->bit_depth_minus8
= byte
& 0xf;
97 if (info
->bit_depth_minus8
> 8) {
98 return AVERROR_INVALIDDATA
;
100 if (info
->bit_depth_minus8
% 2) {
101 // Odd bit depths are technically valid but not useful here.
102 return AVERROR_INVALIDDATA
;
105 // Ignore capture_time_distance.
106 bytestream2_skip(gbc
, 1);
108 zero
= bytestream2_get_byte(gbc
);
110 return AVERROR_INVALIDDATA
;
115 static int apv_probe(const AVProbeData
*p
)
118 uint32_t au_size
, signature
, pbu_size
;
121 if (p
->buf_size
< 28) {
122 // Too small to fit an APV header.
126 bytestream2_init(&gbc
, p
->buf
, p
->buf_size
);
128 au_size
= bytestream2_get_be32(&gbc
);
133 signature
= bytestream2_get_be32(&gbc
);
134 if (signature
!= APV_SIGNATURE
) {
135 // Signature is mandatory.
138 pbu_size
= bytestream2_get_be32(&gbc
);
144 err
= apv_extract_header_info(&gbc
);
146 // Header does not look like APV.
149 return AVPROBE_SCORE_MAX
;
152 static int apv_read_header(AVFormatContext
*s
)
154 APVDemuxerContext
*apv
= s
->priv_data
;
158 uint32_t au_size
, signature
, pbu_size
;
161 err
= ffio_ensure_seekback(s
->pb
, sizeof(buffer
));
164 size
= ffio_read_size(s
->pb
, buffer
, sizeof(buffer
));
168 bytestream2_init(&gbc
, buffer
, sizeof(buffer
));
170 au_size
= bytestream2_get_be32(&gbc
);
173 return AVERROR_INVALIDDATA
;
175 signature
= bytestream2_get_be32(&gbc
);
176 if (signature
!= APV_SIGNATURE
) {
177 // Signature is mandatory.
178 return AVERROR_INVALIDDATA
;
180 pbu_size
= bytestream2_get_be32(&gbc
);
183 return AVERROR_INVALIDDATA
;
186 st
= avformat_new_stream(s
, NULL
);
188 return AVERROR(ENOMEM
);
190 st
->codecpar
->codec_type
= AVMEDIA_TYPE_VIDEO
;
191 st
->codecpar
->codec_id
= AV_CODEC_ID_APV
;
193 ffstream(st
)->need_parsing
= AVSTREAM_PARSE_HEADERS
;
194 st
->avg_frame_rate
= apv
->framerate
;
195 avpriv_set_pts_info(st
, 64, apv
->framerate
.den
, apv
->framerate
.num
);
197 avio_seek(s
->pb
, -size
, SEEK_CUR
);
202 static int apv_read_packet(AVFormatContext
*s
, AVPacket
*pkt
)
204 uint32_t au_size
, signature
;
207 au_size
= avio_rb32(s
->pb
);
208 if (au_size
== 0 && avio_feof(s
->pb
))
210 if (au_size
< 24 || au_size
> 1 << 26) {
211 av_log(s
, AV_LOG_ERROR
,
212 "APV AU has invalid size: %"PRIu32
"\n", au_size
);
213 return AVERROR_INVALIDDATA
;
216 ret
= av_get_packet(s
->pb
, pkt
, au_size
);
220 pkt
->flags
= AV_PKT_FLAG_KEY
;
222 signature
= AV_RB32(pkt
->data
);
223 if (signature
!= APV_SIGNATURE
) {
224 av_log(s
, AV_LOG_ERROR
, "APV AU has invalid signature.\n");
225 return AVERROR_INVALIDDATA
;
231 #define OFFSET(x) offsetof(APVDemuxerContext, x)
232 #define DEC AV_OPT_FLAG_DECODING_PARAM
233 static const AVOption apv_options
[] = {
234 { "framerate", "set frame rate", OFFSET(framerate
), AV_OPT_TYPE_VIDEO_RATE
, { .str
= "30" }, 0, INT_MAX
, DEC
},
238 static const AVClass apv_demuxer_class
= {
239 .class_name
= "apv demuxer",
240 .item_name
= av_default_item_name
,
241 .option
= apv_options
,
242 .version
= LIBAVUTIL_VERSION_INT
,
245 const FFInputFormat ff_apv_demuxer
= {
247 .p
.long_name
= NULL_IF_CONFIG_SMALL("APV raw bitstream"),
248 .p
.extensions
= "apv",
249 .p
.flags
= AVFMT_GENERIC_INDEX
| AVFMT_NOTIMESTAMPS
,
250 .p
.priv_class
= &apv_demuxer_class
,
251 .priv_data_size
= sizeof(APVDemuxerContext
),
252 .read_probe
= apv_probe
,
253 .read_header
= apv_read_header
,
254 .read_packet
= apv_read_packet
,