FFmpeg
rtpdec_vc2hq.c
Go to the documentation of this file.
1 /*
2  * RTP parser for VC-2 HQ payload format (draft version 1) - experimental
3  * Copyright (c) 2016 Thomas Volkert <thomas@netzeal.de>
4  *
5  * This file is part of FFmpeg.
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #include "libavutil/intreadwrite.h"
23 #include "libavcodec/dirac.h"
24 
25 #include "avio_internal.h"
26 #include "rtpdec_formats.h"
27 
28 #define RTP_VC2HQ_PL_HEADER_SIZE 4
29 
30 #define DIRAC_DATA_UNIT_HEADER_SIZE 13
31 #define DIRAC_PIC_NR_SIZE 4
32 #define DIRAC_RTP_PCODE_HQ_PIC_FRAGMENT 0xEC
33 
34 struct PayloadContext {
36  uint32_t frame_size;
37  uint32_t frame_nr;
38  uint32_t timestamp;
39  uint32_t last_unit_size;
41 };
42 
43 static const uint8_t start_sequence[] = { 'B', 'B', 'C', 'D' };
44 
46  uint8_t parse_code, uint32_t data_unit_size)
47 {
48  memcpy(buf, start_sequence, sizeof(start_sequence));
49  buf[4] = parse_code;
50  AV_WB32(&buf[5], data_unit_size);
51  AV_WB32(&buf[9], pl_ctx->last_unit_size);
52 
53  pl_ctx->last_unit_size = data_unit_size;
54 }
55 
57  const uint8_t *buf, int len)
58 {
59  int res;
61 
62  if ((res = av_new_packet(pkt, DIRAC_DATA_UNIT_HEADER_SIZE + len)) < 0)
63  return res;
64 
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;
69 
70  pl_ctx->seen_sequence_header = 1;
71 
72  return 0;
73 }
74 
76 {
77  int res;
78  uint32_t size = 0;
79 
80  /* create A/V packet */
81  if ((res = av_new_packet(pkt, DIRAC_DATA_UNIT_HEADER_SIZE)) < 0)
82  return res;
83 
84  fill_parse_info_header(pl_ctx, pkt->data, 0x10, size);
85  pkt->stream_index = st->index;
86 
87  pl_ctx->seen_sequence_header = 0;
88 
89  return 0;
90 }
91 
93  AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len,
94  int flags)
95 {
96  int res;
97  uint32_t pic_nr;
98  uint16_t frag_len;
99  uint16_t no_slices;
100 
101  /* sanity check for size of input packet: 16 bytes header in any case as minimum */
102  if (len < 16) {
103  av_log(ctx, AV_LOG_ERROR, "Too short RTP/VC2hq packet, got %d bytes\n", len);
104  return AVERROR_INVALIDDATA;
105  }
106 
107  pic_nr = AV_RB32(&buf[4]);
108  frag_len = AV_RB16(&buf[12]);
109  no_slices = AV_RB16(&buf[14]);
110 
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);
114  }
115 
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;
121  }
122 
123  /* start frame buffering with new dynamic buffer */
124  if (!pl_ctx->buf) {
125 
126  res = avio_open_dyn_buf(&pl_ctx->buf);
127  if (res < 0)
128  return res;
129 
130  /* reserve memory for frame header */
131  res = avio_seek(pl_ctx->buf, DIRAC_DATA_UNIT_HEADER_SIZE + DIRAC_PIC_NR_SIZE, SEEK_SET);
132  if (res < 0)
133  return res;
134 
135  pl_ctx->frame_nr = pic_nr;
136  pl_ctx->timestamp = *timestamp;
138  }
139 
140  avio_write(pl_ctx->buf, buf + 16 /* skip pl header */, frag_len);
141  pl_ctx->frame_size += frag_len;
142 
143  return AVERROR(EAGAIN);
144  } else {
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;
148  }
149 
150  /* transform parameters were missed, no buffer available */
151  if (!pl_ctx->buf)
152  return AVERROR_INVALIDDATA;
153 
154  avio_write(pl_ctx->buf, buf + 20 /* skip pl header */, frag_len);
155  pl_ctx->frame_size += frag_len;
156 
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);
161  }
162 
163  /* close frame buffering and create A/V packet */
164  res = ff_rtp_finalize_packet(pkt, &pl_ctx->buf, st->index);
165  if (res < 0)
166  return res;
167 
169  AV_WB32(&pkt->data[13], pl_ctx->frame_nr);
170 
171  pl_ctx->frame_size = 0;
172 
173  return 0;
174 }
175 
177  AVStream *st, AVPacket *pkt, uint32_t *timestamp,
178  const uint8_t *buf, int len, uint16_t seq,
179  int flags)
180 {
181  uint8_t parse_code = 0;
182  int res = 0;
183 
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;
188  }
189 
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;
194  }
195 
196  parse_code = buf[3];
197 
198  /* wait for next sequence header? */
199  if (pl_ctx->seen_sequence_header || parse_code == DIRAC_PCODE_SEQ_HEADER) {
200  switch(parse_code) {
201  /* sequence header */
204  break;
205  /* end of sequence */
206  case DIRAC_PCODE_END_SEQ:
207  res = vc2hq_mark_end_of_sequence(pl_ctx, st, pkt);
208  break;
209  /* HQ picture fragment */
211  res = vc2hq_handle_frame_fragment(ctx, pl_ctx, st, pkt, timestamp, buf, len, flags);
212  break;
213  }
214  }
215 
216  return res;
217 }
218 
220  .enc_name = "VC2",
221  .codec_type = AVMEDIA_TYPE_VIDEO,
222  .codec_id = AV_CODEC_ID_DIRAC,
223  .priv_data_size = sizeof(PayloadContext),
225 };
AVPacket pkt
Definition: rtpdec_qt.c:37
Bytestream IO Context.
Definition: avio.h:161
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
#define DIRAC_PIC_NR_SIZE
Definition: rtpdec_vc2hq.c:31
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
RTP/JPEG specific private data.
Definition: rdt.c:83
int index
stream index in AVFormatContext
Definition: avformat.h:882
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:246
#define RTP_VC2HQ_PL_HEADER_SIZE
Definition: rtpdec_vc2hq.c:28
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:87
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1391
Format I/O context.
Definition: avformat.h:1358
uint8_t
Interface to Dirac Decoder/Encoder.
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:87
static int vc2hq_handle_frame_fragment(AVFormatContext *ctx, PayloadContext *pl_ctx, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, int flags)
Definition: rtpdec_vc2hq.c:92
int seen_sequence_header
Definition: rtpdec_vc2hq.c:40
uint8_t * data
Definition: avcodec.h:1477
#define DIRAC_RTP_PCODE_HQ_PIC_FRAGMENT
Definition: rtpdec_vc2hq.c:32
ptrdiff_t size
Definition: opengl_enc.c:100
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:218
static int vc2hq_handle_packet(AVFormatContext *ctx, PayloadContext *pl_ctx, AVStream *st, AVPacket *pkt, uint32_t *timestamp, const uint8_t *buf, int len, uint16_t seq, int flags)
Definition: rtpdec_vc2hq.c:176
#define av_log(a,...)
int av_new_packet(AVPacket *pkt, int size)
Allocate the payload of a packet and initialize its fields with default values.
Definition: avpacket.c:86
uint32_t timestamp
current frame timestamp
Definition: rtpdec_ac3.c:31
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define RTP_FLAG_MARKER
RTP marker bit was set for this packet.
Definition: rtpdec.h:93
static void fill_parse_info_header(PayloadContext *pl_ctx, uint8_t *buf, uint8_t parse_code, uint32_t data_unit_size)
Definition: rtpdec_vc2hq.c:45
unsigned int frame_size
uint32_t frame_size
Definition: rtpdec_vc2hq.c:36
AVFormatContext * ctx
Definition: movenc.c:48
static const uint8_t start_sequence[]
Definition: rtpdec_vc2hq.c:43
void ffio_free_dyn_buf(AVIOContext **s)
Free a dynamic buffer.
Definition: aviobuf.c:1450
Stream structure.
Definition: avformat.h:881
#define AV_WB32(p, v)
Definition: intreadwrite.h:419
uint8_t * buf
the temporary storage buffer
Definition: rtpdec_asf.c:183
const char * enc_name
Definition: rtpdec.h:116
#define flags(name, subs,...)
Definition: cbs_av1.c:561
static int vc2hq_handle_sequence_header(PayloadContext *pl_ctx, AVStream *st, AVPacket *pkt, const uint8_t *buf, int len)
Definition: rtpdec_vc2hq.c:56
#define DIRAC_DATA_UNIT_HEADER_SIZE
Definition: rtpdec_vc2hq.c:30
int ff_rtp_finalize_packet(AVPacket *pkt, AVIOContext **dyn_buf, int stream_idx)
Close the dynamic buffer and make a packet from it.
Definition: rtpdec.c:927
static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index)
Parse a packet, add all split parts to parse_queue.
Definition: utils.c:1438
static int vc2hq_mark_end_of_sequence(PayloadContext *pl_ctx, AVStream *st, AVPacket *pkt)
Definition: rtpdec_vc2hq.c:75
uint32_t frame_nr
Definition: rtpdec_vc2hq.c:37
int stream_index
Definition: avcodec.h:1479
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Frame references ownership and permissions
const RTPDynamicProtocolHandler ff_vc2hq_dynamic_handler
Definition: rtpdec_vc2hq.c:219
uint32_t last_unit_size
Definition: rtpdec_vc2hq.c:39
This structure stores compressed data.
Definition: avcodec.h:1454