FFmpeg  4.0
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
int size
#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:874
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
int avio_open_dyn_buf(AVIOContext **s)
Open a write only memory stream.
Definition: aviobuf.c:1391
Format I/O context.
Definition: avformat.h:1342
uint8_t
Interface to Dirac Decoder/Encoder.
#define AV_RB32
Definition: intreadwrite.h:130
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:1430
static int flags
Definition: log.c:55
#define DIRAC_RTP_PCODE_HQ_PIC_FRAGMENT
Definition: rtpdec_vc2hq.c:32
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
#define AV_RB16
Definition: intreadwrite.h:53
#define AVERROR(e)
Definition: error.h:43
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:873
#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
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:1437
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:1432
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:1407