2 * TechnoTrend PVA (.pva) demuxer
3 * Copyright (c) 2007, 2008 Ivo van Poorten
5 * This file is part of Libav.
7 * Libav is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * Libav is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with Libav; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
26 #define PVA_MAX_PAYLOAD_LENGTH 0x17f8
27 #define PVA_VIDEO_PAYLOAD 0x01
28 #define PVA_AUDIO_PAYLOAD 0x02
29 #define PVA_MAGIC (('A' << 8) + 'V')
35 static int pva_probe(AVProbeData
* pd
) {
36 unsigned char *buf
= pd
->buf
;
38 if (AV_RB16(buf
) == PVA_MAGIC
&& buf
[2] && buf
[2] < 3 && buf
[4] == 0x55)
39 return AVPROBE_SCORE_MAX
/ 2;
44 static int pva_read_header(AVFormatContext
*s
) {
47 if (!(st
= avformat_new_stream(s
, NULL
)))
48 return AVERROR(ENOMEM
);
49 st
->codec
->codec_type
= AVMEDIA_TYPE_VIDEO
;
50 st
->codec
->codec_id
= AV_CODEC_ID_MPEG2VIDEO
;
51 st
->need_parsing
= AVSTREAM_PARSE_FULL
;
52 avpriv_set_pts_info(st
, 32, 1, 90000);
53 av_add_index_entry(st
, 0, 0, 0, 0, AVINDEX_KEYFRAME
);
55 if (!(st
= avformat_new_stream(s
, NULL
)))
56 return AVERROR(ENOMEM
);
57 st
->codec
->codec_type
= AVMEDIA_TYPE_AUDIO
;
58 st
->codec
->codec_id
= AV_CODEC_ID_MP2
;
59 st
->need_parsing
= AVSTREAM_PARSE_FULL
;
60 avpriv_set_pts_info(st
, 33, 1, 90000);
61 av_add_index_entry(st
, 0, 0, 0, 0, AVINDEX_KEYFRAME
);
63 /* the parameters will be extracted from the compressed bitstream */
67 #define pva_log if (read_packet) av_log
69 static int read_part_of_packet(AVFormatContext
*s
, int64_t *pts
,
70 int *len
, int *strid
, int read_packet
) {
71 AVIOContext
*pb
= s
->pb
;
72 PVAContext
*pvactx
= s
->priv_data
;
73 int syncword
, streamid
, reserved
, flags
, length
, pts_flag
;
74 int64_t pva_pts
= AV_NOPTS_VALUE
, startpos
;
77 startpos
= avio_tell(pb
);
79 syncword
= avio_rb16(pb
);
80 streamid
= avio_r8(pb
);
81 avio_r8(pb
); /* counter not used */
82 reserved
= avio_r8(pb
);
84 length
= avio_rb16(pb
);
86 pts_flag
= flags
& 0x10;
88 if (syncword
!= PVA_MAGIC
) {
89 pva_log(s
, AV_LOG_ERROR
, "invalid syncword\n");
92 if (streamid
!= PVA_VIDEO_PAYLOAD
&& streamid
!= PVA_AUDIO_PAYLOAD
) {
93 pva_log(s
, AV_LOG_ERROR
, "invalid streamid\n");
96 if (reserved
!= 0x55) {
97 pva_log(s
, AV_LOG_WARNING
, "expected reserved byte to be 0x55\n");
99 if (length
> PVA_MAX_PAYLOAD_LENGTH
) {
100 pva_log(s
, AV_LOG_ERROR
, "invalid payload length %u\n", length
);
104 if (streamid
== PVA_VIDEO_PAYLOAD
&& pts_flag
) {
105 pva_pts
= avio_rb32(pb
);
107 } else if (streamid
== PVA_AUDIO_PAYLOAD
) {
108 /* PVA Audio Packets either start with a signaled PES packet or
109 * are a continuation of the previous PES packet. New PES packets
110 * always start at the beginning of a PVA Packet, never somewhere in
112 if (!pvactx
->continue_pes
) {
113 int pes_signal
, pes_header_data_length
, pes_packet_length
,
115 unsigned char pes_header_data
[256];
117 pes_signal
= avio_rb24(pb
);
119 pes_packet_length
= avio_rb16(pb
);
120 pes_flags
= avio_rb16(pb
);
121 pes_header_data_length
= avio_r8(pb
);
123 if (pes_signal
!= 1) {
124 pva_log(s
, AV_LOG_WARNING
, "expected signaled PES packet, "
125 "trying to recover\n");
126 avio_skip(pb
, length
- 9);
132 avio_read(pb
, pes_header_data
, pes_header_data_length
);
133 length
-= 9 + pes_header_data_length
;
135 pes_packet_length
-= 3 + pes_header_data_length
;
137 pvactx
->continue_pes
= pes_packet_length
;
139 if (pes_flags
& 0x80 && (pes_header_data
[0] & 0xf0) == 0x20)
140 pva_pts
= ff_parse_pes_pts(pes_header_data
);
143 pvactx
->continue_pes
-= length
;
145 if (pvactx
->continue_pes
< 0) {
146 pva_log(s
, AV_LOG_WARNING
, "audio data corruption\n");
147 pvactx
->continue_pes
= 0;
151 if (pva_pts
!= AV_NOPTS_VALUE
)
152 av_add_index_entry(s
->streams
[streamid
-1], startpos
, pva_pts
, 0, 0, AVINDEX_KEYFRAME
);
160 static int pva_read_packet(AVFormatContext
*s
, AVPacket
*pkt
) {
161 AVIOContext
*pb
= s
->pb
;
163 int ret
, length
, streamid
;
165 if (read_part_of_packet(s
, &pva_pts
, &length
, &streamid
, 1) < 0 ||
166 (ret
= av_get_packet(pb
, pkt
, length
)) <= 0)
169 pkt
->stream_index
= streamid
- 1;
175 static int64_t pva_read_timestamp(struct AVFormatContext
*s
, int stream_index
,
176 int64_t *pos
, int64_t pos_limit
) {
177 AVIOContext
*pb
= s
->pb
;
178 PVAContext
*pvactx
= s
->priv_data
;
179 int length
, streamid
;
180 int64_t res
= AV_NOPTS_VALUE
;
182 pos_limit
= FFMIN(*pos
+PVA_MAX_PAYLOAD_LENGTH
*8, (uint64_t)*pos
+pos_limit
);
184 while (*pos
< pos_limit
) {
185 res
= AV_NOPTS_VALUE
;
186 avio_seek(pb
, *pos
, SEEK_SET
);
188 pvactx
->continue_pes
= 0;
189 if (read_part_of_packet(s
, &res
, &length
, &streamid
, 0)) {
193 if (streamid
- 1 != stream_index
|| res
== AV_NOPTS_VALUE
) {
194 *pos
= avio_tell(pb
) + length
;
200 pvactx
->continue_pes
= 0;
204 AVInputFormat ff_pva_demuxer
= {
206 .long_name
= NULL_IF_CONFIG_SMALL("TechnoTrend PVA"),
207 .priv_data_size
= sizeof(PVAContext
),
208 .read_probe
= pva_probe
,
209 .read_header
= pva_read_header
,
210 .read_packet
= pva_read_packet
,
211 .read_timestamp
= pva_read_timestamp
,