FFmpeg
media100.c
Go to the documentation of this file.
1 /*
2  * Media 100 decoder
3  * Copyright (c) 2022 Paul B Mahol
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 /**
23  * @file
24  * Media 100 decoder.
25  */
26 
27 #include <inttypes.h>
28 
29 #include "libavutil/intreadwrite.h"
30 #include "avcodec.h"
31 #include "bytestream.h"
32 #include "codec_internal.h"
33 
34 typedef struct Media100Context {
35  AVCodecContext *avctx; // wrapper context for mjpegb
38 
40 {
41  Media100Context *ctx = avctx->priv_data;
42  const AVCodec *codec;
43  int ret;
44 
46  if (!codec)
47  return AVERROR_BUG;
48  ctx->avctx = avcodec_alloc_context3(codec);
49  if (!ctx->avctx)
50  return AVERROR(ENOMEM);
51  ctx->avctx->thread_count = 1;
52  ctx->avctx->flags = avctx->flags;
53  ctx->avctx->flags2 = avctx->flags2;
54  ctx->avctx->width = ctx->avctx->coded_width = avctx->width;
55  ctx->avctx->height = ctx->avctx->coded_height = avctx->height;
56 
57  ret = avcodec_open2(ctx->avctx, codec, NULL);
58  if (ret < 0)
59  return ret;
60 
61  ctx->pkt = av_packet_alloc();
62  if (!ctx->pkt)
63  return AVERROR(ENOMEM);
64 
65  return 0;
66 }
67 
69  AVFrame *frame, int *got_frame,
70  AVPacket *avpkt)
71 {
72  Media100Context *ctx = avctx->priv_data;
73  unsigned second_field_offset = 0;
74  unsigned next_field = 0;
75  unsigned dht_offset[2];
76  unsigned dqt_offset[2];
77  unsigned sod_offset[2];
78  unsigned sof_offset[2];
79  unsigned sos_offset[2];
80  unsigned field = 0;
81  GetByteContext gb;
82  PutByteContext pb;
83  AVPacket *pkt;
84  int ret;
85 
86  if (avpkt->size + 1024 > ctx->pkt->size) {
87  ret = av_grow_packet(ctx->pkt, avpkt->size + 1024 - ctx->pkt->size);
88  if (ret < 0)
89  return ret;
90  }
91 
93  if (ret < 0)
94  return ret;
95 
96  bytestream2_init(&gb, avpkt->data, avpkt->size);
97  bytestream2_init_writer(&pb, ctx->pkt->data, ctx->pkt->size);
98 
99 second_field:
100  bytestream2_put_be32(&pb, 0);
101  bytestream2_put_be32(&pb, AV_RB32("mjpg"));
102  bytestream2_put_be32(&pb, 0);
103  bytestream2_put_be32(&pb, 0);
104  for (int i = 0; i < 6; i++)
105  bytestream2_put_be32(&pb, 0);
106 
107  sof_offset[field] = bytestream2_tell_p(&pb);
108  bytestream2_put_be16(&pb, 17);
109  bytestream2_put_byte(&pb, 8);
110  bytestream2_put_be16(&pb, avctx->height / 2);
111  bytestream2_put_be16(&pb, avctx->width);
112  bytestream2_put_byte(&pb, 3);
113  bytestream2_put_byte(&pb, 1);
114  bytestream2_put_byte(&pb, 0x21);
115  bytestream2_put_byte(&pb, 0);
116  bytestream2_put_byte(&pb, 2);
117  bytestream2_put_byte(&pb, 0x11);
118  bytestream2_put_byte(&pb, 1);
119  bytestream2_put_byte(&pb, 3);
120  bytestream2_put_byte(&pb, 0x11);
121  bytestream2_put_byte(&pb, 1);
122 
123  sos_offset[field] = bytestream2_tell_p(&pb);
124  bytestream2_put_be16(&pb, 12);
125  bytestream2_put_byte(&pb, 3);
126  bytestream2_put_byte(&pb, 1);
127  bytestream2_put_byte(&pb, 0);
128  bytestream2_put_byte(&pb, 2);
129  bytestream2_put_byte(&pb, 0x11);
130  bytestream2_put_byte(&pb, 3);
131  bytestream2_put_byte(&pb, 0x11);
132  bytestream2_put_byte(&pb, 0);
133  bytestream2_put_byte(&pb, 0);
134  bytestream2_put_byte(&pb, 0);
135 
136  dqt_offset[field] = bytestream2_tell_p(&pb);
137  bytestream2_put_be16(&pb, 132);
138  bytestream2_put_byte(&pb, 0);
139  bytestream2_skip(&gb, 4);
140  for (int i = 0; i < 64; i++)
141  bytestream2_put_byte(&pb, bytestream2_get_be32(&gb));
142  bytestream2_put_byte(&pb, 1);
143  for (int i = 0; i < 64; i++)
144  bytestream2_put_byte(&pb, bytestream2_get_be32(&gb));
145 
146  dht_offset[field] = 0;
147  sod_offset[field] = bytestream2_tell_p(&pb);
148 
149  for (int i = bytestream2_tell(&gb) + 8; next_field == 0 && i < avpkt->size - 4; i++) {
150  if (AV_RB32(avpkt->data + i) == 0x00000001) {
151  next_field = i;
152  break;
153  }
154  }
155 
156  bytestream2_skip(&gb, 8);
157  bytestream2_copy_buffer(&pb, &gb, next_field - bytestream2_tell(&gb));
158  bytestream2_put_be64(&pb, 0);
159 
160  if (field == 0) {
161  field = 1;
162  second_field_offset = bytestream2_tell_p(&pb);
163  next_field = avpkt->size;
164  goto second_field;
165  }
166 
167  pkt = ctx->pkt;
168 
169  AV_WB32(pkt->data + 8, second_field_offset);
170  AV_WB32(pkt->data + 12, second_field_offset);
171  AV_WB32(pkt->data + 16, second_field_offset);
172  AV_WB32(pkt->data + 20, dqt_offset[0]);
173  AV_WB32(pkt->data + 24, dht_offset[0]);
174  AV_WB32(pkt->data + 28, sof_offset[0]);
175  AV_WB32(pkt->data + 32, sos_offset[0]);
176  AV_WB32(pkt->data + 36, sod_offset[0]);
177 
178  AV_WB32(pkt->data + second_field_offset + 8, bytestream2_tell_p(&pb) - second_field_offset);
179  AV_WB32(pkt->data + second_field_offset + 12, bytestream2_tell_p(&pb) - second_field_offset);
180  AV_WB32(pkt->data + second_field_offset + 16, 0);
181  AV_WB32(pkt->data + second_field_offset + 20, dqt_offset[1] - second_field_offset);
182  AV_WB32(pkt->data + second_field_offset + 24, dht_offset[1]);
183  AV_WB32(pkt->data + second_field_offset + 28, sof_offset[1] - second_field_offset);
184  AV_WB32(pkt->data + second_field_offset + 32, sos_offset[1] - second_field_offset);
185  AV_WB32(pkt->data + second_field_offset + 36, sod_offset[1] - second_field_offset);
186 
187  pkt->size = bytestream2_tell_p(&pb);
188 
189  ret = avcodec_send_packet(ctx->avctx, pkt);
190  if (ret < 0) {
191  av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n");
192  return ret;
193  }
194 
195  ret = avcodec_receive_frame(ctx->avctx, frame);
196  if (ret < 0)
197  return ret;
198 
199  *got_frame = 1;
200 
201  return avpkt->size;
202 }
203 
205 {
206  Media100Context *ctx = avctx->priv_data;
207 
208  avcodec_free_context(&ctx->avctx);
209  av_packet_free(&ctx->pkt);
210 
211  return 0;
212 }
213 
215  .p.name = "media100",
216  CODEC_LONG_NAME("Media 100"),
217  .p.type = AVMEDIA_TYPE_VIDEO,
218  .p.id = AV_CODEC_ID_MEDIA100,
219  .priv_data_size = sizeof(Media100Context),
221  .close = media100_decode_end,
223  .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
224 };
AVCodec
AVCodec.
Definition: codec.h:204
FF_CODEC_CAP_INIT_CLEANUP
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
Definition: codec_internal.h:42
media100_decode_init
static av_cold int media100_decode_init(AVCodecContext *avctx)
Definition: media100.c:39
AVERROR
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
GetByteContext
Definition: bytestream.h:33
av_grow_packet
int av_grow_packet(AVPacket *pkt, int grow_by)
Increase packet size, correctly zeroing padding.
Definition: avpacket.c:120
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:330
AVPacket::data
uint8_t * data
Definition: packet.h:374
bytestream2_tell_p
static av_always_inline int bytestream2_tell_p(PutByteContext *p)
Definition: bytestream.h:197
media100_decode_frame
static int media100_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt)
Definition: media100.c:68
FFCodec
Definition: codec_internal.h:127
AV_CODEC_ID_MEDIA100
@ AV_CODEC_ID_MEDIA100
Definition: codec_id.h:321
av_packet_free
void av_packet_free(AVPacket **pkt)
Free the packet, if the packet is reference counted, it will be unreferenced first.
Definition: avpacket.c:73
Media100Context
Definition: media100.c:34
bytestream2_skip
static av_always_inline void bytestream2_skip(GetByteContext *g, unsigned int size)
Definition: bytestream.h:168
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:131
Media100Context::avctx
AVCodecContext * avctx
Definition: media100.c:35
AVCodecContext::flags
int flags
AV_CODEC_FLAG_*.
Definition: avcodec.h:511
pkt
AVPacket * pkt
Definition: movenc.c:59
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
av_cold
#define av_cold
Definition: attributes.h:90
ff_media100_decoder
const FFCodec ff_media100_decoder
Definition: media100.c:214
bytestream2_init_writer
static av_always_inline void bytestream2_init_writer(PutByteContext *p, uint8_t *buf, int buf_size)
Definition: bytestream.h:147
avcodec_alloc_context3
AVCodecContext * avcodec_alloc_context3(const AVCodec *codec)
Allocate an AVCodecContext and set its fields to default values.
Definition: options.c:149
FF_CODEC_DECODE_CB
#define FF_CODEC_DECODE_CB(func)
Definition: codec_internal.h:306
intreadwrite.h
AVFormatContext::flags
int flags
Flags modifying the (de)muxer behaviour.
Definition: avformat.h:1334
init
int(* init)(AVBSFContext *ctx)
Definition: dts2pts_bsf.c:365
avcodec_receive_frame
int attribute_align_arg avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
Return decoded output data from a decoder or encoder (when the AV_CODEC_FLAG_RECON_FRAME flag is used...
Definition: avcodec.c:709
ctx
AVFormatContext * ctx
Definition: movenc.c:48
field
it s the only field you need to keep assuming you have a context There is some magic you don t need to care about around this field
Definition: writing_filters.txt:78
CODEC_LONG_NAME
#define CODEC_LONG_NAME(str)
Definition: codec_internal.h:272
NULL
#define NULL
Definition: coverity.c:32
avcodec_free_context
void avcodec_free_context(AVCodecContext **avctx)
Free the codec context and everything associated with it and write NULL to the provided pointer.
Definition: options.c:164
avcodec_open2
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
Initialize the AVCodecContext to use the given AVCodec.
Definition: avcodec.c:115
bytestream2_tell
static av_always_inline int bytestream2_tell(GetByteContext *g)
Definition: bytestream.h:192
avcodec_find_decoder
const AVCodec * avcodec_find_decoder(enum AVCodecID id)
Find a registered decoder with a matching codec ID.
Definition: allcodecs.c:955
AV_CODEC_ID_MJPEGB
@ AV_CODEC_ID_MJPEGB
Definition: codec_id.h:60
AV_WB32
#define AV_WB32(p, v)
Definition: intreadwrite.h:419
PutByteContext
Definition: bytestream.h:37
Media100Context::pkt
AVPacket * pkt
Definition: media100.c:36
AVCodecContext::flags2
int flags2
AV_CODEC_FLAG2_*.
Definition: avcodec.h:518
AVPacket::size
int size
Definition: packet.h:375
codec_internal.h
AV_RB32
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:96
av_packet_alloc
AVPacket * av_packet_alloc(void)
Allocate an AVPacket and set its fields to default values.
Definition: avpacket.c:62
avcodec_send_packet
int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt)
Supply raw packet data as input to a decoder.
Definition: decode.c:607
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
AVCodec::name
const char * name
Name of the codec implementation.
Definition: codec.h:211
AVCodecContext::height
int height
Definition: avcodec.h:604
avcodec.h
ret
ret
Definition: filter_design.txt:187
bytestream2_copy_buffer
static av_always_inline unsigned int bytestream2_copy_buffer(PutByteContext *p, GetByteContext *g, unsigned int size)
Definition: bytestream.h:347
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
AVCodecContext
main external API structure.
Definition: avcodec.h:431
av_packet_make_writable
int av_packet_make_writable(AVPacket *pkt)
Create a writable reference for the data described by a given packet, avoiding data copy if possible.
Definition: avpacket.c:504
AVMEDIA_TYPE_VIDEO
@ AVMEDIA_TYPE_VIDEO
Definition: avutil.h:201
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:458
AVPacket
This structure stores compressed data.
Definition: packet.h:351
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:604
bytestream.h
bytestream2_init
static av_always_inline void bytestream2_init(GetByteContext *g, const uint8_t *buf, int buf_size)
Definition: bytestream.h:137
AVERROR_BUG
#define AVERROR_BUG
Internal bug, also see AVERROR_BUG2.
Definition: error.h:52
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
media100_decode_end
static av_cold int media100_decode_end(AVCodecContext *avctx)
Definition: media100.c:204