2 * RTP parser for VC-2 HQ payload format (draft version 1) - experimental
3 * Copyright (c) 2016 Thomas Volkert <thomas@netzeal.de>
5 * This file is part of FFmpeg.
7 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "libavutil/intreadwrite.h"
23 #include "libavcodec/dirac.h"
25 #include "avio_internal.h"
26 #include "rtpdec_formats.h"
28 #define RTP_VC2HQ_PL_HEADER_SIZE 4
30 #define DIRAC_DATA_UNIT_HEADER_SIZE 13
31 #define DIRAC_PIC_NR_SIZE 4
32 #define DIRAC_RTP_PCODE_HQ_PIC_FRAGMENT 0xEC
34 struct PayloadContext
{
39 uint32_t last_unit_size
;
40 int seen_sequence_header
;
43 static const uint8_t start_sequence
[] = { 'B', 'B', 'C', 'D' };
45 static void fill_parse_info_header(PayloadContext
*pl_ctx
, uint8_t *buf
,
46 uint8_t parse_code
, uint32_t data_unit_size
)
48 memcpy(buf
, start_sequence
, sizeof(start_sequence
));
50 AV_WB32(&buf
[5], data_unit_size
);
51 AV_WB32(&buf
[9], pl_ctx
->last_unit_size
);
53 pl_ctx
->last_unit_size
= data_unit_size
;
56 static int vc2hq_handle_sequence_header(PayloadContext
*pl_ctx
, AVStream
*st
, AVPacket
*pkt
,
57 const uint8_t *buf
, int len
)
60 uint32_t size
= DIRAC_DATA_UNIT_HEADER_SIZE
+ len
;
62 if ((res
= av_new_packet(pkt
, DIRAC_DATA_UNIT_HEADER_SIZE
+ len
)) < 0)
65 fill_parse_info_header(pl_ctx
, pkt
->data
, 0x00, size
);
66 /* payload of seq. header */
67 memcpy(pkt
->data
+ DIRAC_DATA_UNIT_HEADER_SIZE
, buf
, len
);
68 pkt
->stream_index
= st
->index
;
70 pl_ctx
->seen_sequence_header
= 1;
75 static int vc2hq_mark_end_of_sequence(PayloadContext
*pl_ctx
, AVStream
*st
, AVPacket
*pkt
)
80 /* create A/V packet */
81 if ((res
= av_new_packet(pkt
, DIRAC_DATA_UNIT_HEADER_SIZE
)) < 0)
84 fill_parse_info_header(pl_ctx
, pkt
->data
, 0x10, size
);
85 pkt
->stream_index
= st
->index
;
87 pl_ctx
->seen_sequence_header
= 0;
92 static int vc2hq_handle_frame_fragment(AVFormatContext
*ctx
, PayloadContext
*pl_ctx
, AVStream
*st
,
93 AVPacket
*pkt
, uint32_t *timestamp
, const uint8_t *buf
, int len
,
101 /* sanity check for size of input packet: 16 bytes header in any case as minimum */
103 av_log(ctx
, AV_LOG_ERROR
, "Too short RTP/VC2hq packet, got %d bytes\n", len
);
104 return AVERROR_INVALIDDATA
;
107 pic_nr
= AV_RB32(&buf
[4]);
108 frag_len
= AV_RB16(&buf
[12]);
109 no_slices
= AV_RB16(&buf
[14]);
111 if (pl_ctx
->buf
&& pl_ctx
->frame_nr
!= pic_nr
) {
112 av_log(ctx
, AV_LOG_WARNING
, "Dropping buffered RTP/VC2hq packet fragments - non-continuous picture numbers\n");
113 ffio_free_dyn_buf(&pl_ctx
->buf
);
116 /* transform parameters? */
117 if (no_slices
== 0) {
118 if (len
< frag_len
+ 16) {
119 av_log(ctx
, AV_LOG_ERROR
, "Too short RTP/VC2hq packet, got %d bytes\n", len
);
120 return AVERROR_INVALIDDATA
;
123 /* start frame buffering with new dynamic buffer */
126 res
= avio_open_dyn_buf(&pl_ctx
->buf
);
130 /* reserve memory for frame header */
131 res
= avio_seek(pl_ctx
->buf
, DIRAC_DATA_UNIT_HEADER_SIZE
+ DIRAC_PIC_NR_SIZE
, SEEK_SET
);
135 pl_ctx
->frame_nr
= pic_nr
;
136 pl_ctx
->timestamp
= *timestamp
;
137 pl_ctx
->frame_size
= DIRAC_DATA_UNIT_HEADER_SIZE
+ DIRAC_PIC_NR_SIZE
;
140 avio_write(pl_ctx
->buf
, buf
+ 16 /* skip pl header */, frag_len
);
141 pl_ctx
->frame_size
+= frag_len
;
143 return AVERROR(EAGAIN
);
145 if (len
< frag_len
+ 20) {
146 av_log(ctx
, AV_LOG_ERROR
, "Too short RTP/VC2hq packet, got %d bytes\n", len
);
147 return AVERROR_INVALIDDATA
;
150 /* transform parameters were missed, no buffer available */
152 return AVERROR_INVALIDDATA
;
154 avio_write(pl_ctx
->buf
, buf
+ 20 /* skip pl header */, frag_len
);
155 pl_ctx
->frame_size
+= frag_len
;
157 /* RTP marker bit means: last fragment of current frame was received;
158 otherwise, an additional fragment is needed for the current frame */
159 if (!(flags
& RTP_FLAG_MARKER
))
160 return AVERROR(EAGAIN
);
163 /* close frame buffering and create A/V packet */
164 res
= ff_rtp_finalize_packet(pkt
, &pl_ctx
->buf
, st
->index
);
168 fill_parse_info_header(pl_ctx
, pkt
->data
, DIRAC_PCODE_PICTURE_HQ
, pl_ctx
->frame_size
);
169 AV_WB32(&pkt
->data
[13], pl_ctx
->frame_nr
);
171 pl_ctx
->frame_size
= 0;
176 static int vc2hq_handle_packet(AVFormatContext
*ctx
, PayloadContext
*pl_ctx
,
177 AVStream
*st
, AVPacket
*pkt
, uint32_t *timestamp
,
178 const uint8_t *buf
, int len
, uint16_t seq
,
181 uint8_t parse_code
= 0;
184 if (pl_ctx
->buf
&& pl_ctx
->timestamp
!= *timestamp
) {
185 av_log(ctx
, AV_LOG_WARNING
, "Dropping buffered RTP/VC2hq packet fragments - non-continuous timestamps\n");
186 ffio_free_dyn_buf(&pl_ctx
->buf
);
187 pl_ctx
->frame_size
= 0;
190 /* sanity check for size of input packet: needed header data as minimum */
191 if (len
< RTP_VC2HQ_PL_HEADER_SIZE
) {
192 av_log(ctx
, AV_LOG_ERROR
, "Too short RTP/VC2hq packet, got %d bytes\n", len
);
193 return AVERROR_INVALIDDATA
;
198 /* wait for next sequence header? */
199 if (pl_ctx
->seen_sequence_header
|| parse_code
== DIRAC_PCODE_SEQ_HEADER
) {
201 /* sequence header */
202 case DIRAC_PCODE_SEQ_HEADER
:
203 res
= vc2hq_handle_sequence_header(pl_ctx
, st
, pkt
, buf
+ RTP_VC2HQ_PL_HEADER_SIZE
, len
- RTP_VC2HQ_PL_HEADER_SIZE
);
205 /* end of sequence */
206 case DIRAC_PCODE_END_SEQ
:
207 res
= vc2hq_mark_end_of_sequence(pl_ctx
, st
, pkt
);
209 /* HQ picture fragment */
210 case DIRAC_RTP_PCODE_HQ_PIC_FRAGMENT
:
211 res
= vc2hq_handle_frame_fragment(ctx
, pl_ctx
, st
, pkt
, timestamp
, buf
, len
, flags
);
219 const RTPDynamicProtocolHandler ff_vc2hq_dynamic_handler
= {
221 .codec_type
= AVMEDIA_TYPE_VIDEO
,
222 .codec_id
= AV_CODEC_ID_DIRAC
,
223 .priv_data_size
= sizeof(PayloadContext
),
224 .parse_packet
= vc2hq_handle_packet