FFmpeg
segafilmenc.c
Go to the documentation of this file.
1 /*
2  * Sega FILM Format (CPK) Muxer
3  * Copyright (C) 2003 The FFmpeg project
4  * Copyright (C) 2018 Misty De Meo
5  *
6  * This file is part of FFmpeg.
7  *
8  * FFmpeg is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * FFmpeg is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with FFmpeg; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 /**
24  * @file
25  * Sega FILM (.cpk) file muxer
26  * @author Misty De Meo <misty@brew.sh>
27  *
28  * @see For more information regarding the Sega FILM file format, visit:
29  * http://wiki.multimedia.cx/index.php?title=Sega_FILM
30  */
31 
32 #include "libavutil/intreadwrite.h"
33 #include "avformat.h"
34 #include "internal.h"
35 #include "avio_internal.h"
36 
37 typedef struct FILMPacket {
38  int audio;
39  int keyframe;
44  struct FILMPacket *next;
45 } FILMPacket;
46 
47 typedef struct FILMOutputContext {
48  const AVClass *class;
51  int64_t stab_pos;
54  int64_t packet_count;
56 
58 {
59  AVIOContext *pb = format_context->pb;
60  /* The bits in these two 32-bit integers contain info about the contents of this sample */
61  int32_t info1 = 0;
62  int32_t info2 = 0;
63 
64  if (pkt->audio) {
65  /* Always the same, carries no more information than "this is audio" */
66  info1 = 0xFFFFFFFF;
67  info2 = 1;
68  } else {
69  info1 = pkt->pts;
70  info2 = pkt->duration;
71  /* The top bit being set indicates a key frame */
72  if (!pkt->keyframe)
73  info1 |= (1 << 31);
74  }
75 
76  /* Write the 16-byte sample info packet to the STAB chunk in the header */
77  avio_wb32(pb, pkt->index);
78  avio_wb32(pb, pkt->size);
79  avio_wb32(pb, info1);
80  avio_wb32(pb, info2);
81 
82  return 0;
83 }
84 
85 static int film_write_packet(AVFormatContext *format_context, AVPacket *pkt)
86 {
87  FILMPacket *metadata;
88  AVIOContext *pb = format_context->pb;
89  FILMOutputContext *film = format_context->priv_data;
90  int encoded_buf_size = 0;
91  enum AVCodecID codec_id;
92 
93  /* Track the metadata used to write the header and add it to the linked list */
94  metadata = av_mallocz(sizeof(FILMPacket));
95  if (!metadata)
96  return AVERROR(ENOMEM);
97  metadata->audio = pkt->stream_index == film->audio_index;
98  metadata->keyframe = pkt->flags & AV_PKT_FLAG_KEY;
99  metadata->pts = pkt->pts;
100  metadata->duration = pkt->duration;
101  metadata->size = pkt->size;
102  if (film->last == NULL) {
103  metadata->index = 0;
104  } else {
105  metadata->index = film->last->index + film->last->size;
106  film->last->next = metadata;
107  }
108  metadata->next = NULL;
109  if (film->start == NULL)
110  film->start = metadata;
111  film->packet_count++;
112  film->last = metadata;
113 
114  codec_id = format_context->streams[pkt->stream_index]->codecpar->codec_id;
115 
116  /* Sega Cinepak has an extra two-byte header; write dummy data there,
117  * then adjust the cvid header to accommodate for the extra size */
118  if (codec_id == AV_CODEC_ID_CINEPAK) {
119  encoded_buf_size = AV_RB24(&pkt->data[1]);
120  /* Already Sega Cinepak, so no need to reformat the packets */
121  if (encoded_buf_size != pkt->size && (pkt->size % encoded_buf_size) != 0) {
122  avio_write(pb, pkt->data, pkt->size);
123  } else {
124  uint8_t padding[2] = {0, 0};
125  /* In Sega Cinepak, the reported size in the Cinepak header is
126  * 8 bytes too short. However, the size in the STAB section of the header
127  * is correct, taking into account the extra two bytes. */
128  AV_WB24(&pkt->data[1], pkt->size - 8 + 2);
129  metadata->size += 2;
130 
131  avio_write(pb, pkt->data, 10);
132  avio_write(pb, padding, 2);
133  avio_write(pb, &pkt->data[10], pkt->size - 10);
134  }
135  } else {
136  /* Other formats can just be written as-is */
137  avio_write(pb, pkt->data, pkt->size);
138  }
139 
140  return 0;
141 }
142 
144 {
145  /* 0 (PCM) and 2 (ADX) are the only known values */
146  switch (codec_id) {
149  return 0;
150  break;
152  return 2;
153  break;
154  default:
155  return -1;
156  }
157 }
158 
159 static int film_init(AVFormatContext *format_context)
160 {
161  AVStream *audio = NULL;
162  FILMOutputContext *film = format_context->priv_data;
163  film->audio_index = -1;
164  film->video_index = -1;
165  film->stab_pos = 0;
166  film->packet_count = 0;
167  film->start = NULL;
168  film->last = NULL;
169 
170  for (int i = 0; i < format_context->nb_streams; i++) {
171  AVStream *st = format_context->streams[i];
172  if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
173  if (film->audio_index > -1) {
174  av_log(format_context, AV_LOG_ERROR, "Sega FILM allows a maximum of one audio stream.\n");
175  return AVERROR(EINVAL);
176  }
177  film->audio_index = i;
178  audio = st;
179  }
180 
181  if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
182  if (film->video_index > -1) {
183  av_log(format_context, AV_LOG_ERROR, "Sega FILM allows a maximum of one video stream.\n");
184  return AVERROR(EINVAL);
185  }
186  film->video_index = i;
187  }
188 
189  if (film->video_index == -1) {
190  av_log(format_context, AV_LOG_ERROR, "No video stream present.\n");
191  return AVERROR(EINVAL);
192  }
193  }
194 
195  if (audio != NULL && get_audio_codec_id(audio->codecpar->codec_id) < 0) {
196  av_log(format_context, AV_LOG_ERROR, "Incompatible audio stream format.\n");
197  return AVERROR(EINVAL);
198  }
199 
200  return 0;
201 }
202 
203 static int shift_data(AVFormatContext *format_context, int64_t shift_size)
204 {
205  int ret = 0;
206  int64_t pos, pos_end = avio_tell(format_context->pb);
207  uint8_t *buf, *read_buf[2];
208  int read_buf_id = 0;
209  int read_size[2];
210  AVIOContext *read_pb;
211 
212  buf = av_malloc(shift_size * 2);
213  if (!buf)
214  return AVERROR(ENOMEM);
215  read_buf[0] = buf;
216  read_buf[1] = buf + shift_size;
217 
218  /* Write the header at the beginning of the file, shifting all content as necessary;
219  * based on the approach used by MOV faststart. */
220  avio_flush(format_context->pb);
221  ret = format_context->io_open(format_context, &read_pb, format_context->url, AVIO_FLAG_READ, NULL);
222  if (ret < 0) {
223  av_log(format_context, AV_LOG_ERROR, "Unable to re-open %s output file to "
224  "write the header\n", format_context->url);
225  av_free(buf);
226  return ret;
227  }
228 
229  /* mark the end of the shift to up to the last data we wrote, and get ready
230  * for writing */
231  pos_end = avio_tell(format_context->pb);
232  avio_seek(format_context->pb, shift_size, SEEK_SET);
233 
234  /* start reading at where the new header will be placed */
235  avio_seek(read_pb, 0, SEEK_SET);
236  pos = avio_tell(read_pb);
237 
238 #define READ_BLOCK do { \
239  read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], shift_size); \
240  read_buf_id ^= 1; \
241 } while (0)
242 
243  /* shift data by chunk of at most shift_size */
244  READ_BLOCK;
245  do {
246  int n;
247  READ_BLOCK;
248  n = read_size[read_buf_id];
249  if (n <= 0)
250  break;
251  avio_write(format_context->pb, read_buf[read_buf_id], n);
252  pos += n;
253  } while (pos < pos_end);
254  ff_format_io_close(format_context, &read_pb);
255 
256  av_free(buf);
257  return 0;
258 }
259 
260 static int film_write_header(AVFormatContext *format_context)
261 {
262  int ret = 0;
263  int64_t sample_table_size, stabsize, headersize;
264  int8_t audio_codec;
265  AVIOContext *pb = format_context->pb;
266  FILMOutputContext *film = format_context->priv_data;
267  FILMPacket *prev, *packet;
268  AVStream *audio = NULL;
269  AVStream *video = NULL;
270 
271  /* Calculate how much we need to reserve for the header;
272  * this is the amount the rest of the data will be shifted up by. */
273  sample_table_size = film->packet_count * 16;
274  stabsize = 16 + sample_table_size;
275  headersize = 16 + /* FILM header base */
276  32 + /* FDSC chunk */
277  stabsize;
278 
279  ret = shift_data(format_context, headersize);
280  if (ret < 0)
281  return ret;
282  /* Seek back to the beginning to start writing the header now */
283  avio_seek(pb, 0, SEEK_SET);
284 
285  if (film->audio_index > -1)
286  audio = format_context->streams[film->audio_index];
287  if (film->video_index > -1)
288  video = format_context->streams[film->video_index];
289 
290  if (audio != NULL) {
291  audio_codec = get_audio_codec_id(audio->codecpar->codec_id);
292  if (audio_codec < 0) {
293  av_log(format_context, AV_LOG_ERROR, "Incompatible audio stream format.\n");
294  return AVERROR(EINVAL);
295  }
296  }
297 
298  if (video->codecpar->format != AV_PIX_FMT_RGB24) {
299  av_log(format_context, AV_LOG_ERROR, "Pixel format must be rgb24.\n");
300  return AVERROR(EINVAL);
301  }
302 
303  /* First, write the FILM header; this is very simple */
304 
305  ffio_wfourcc(pb, "FILM");
306  avio_wb32(pb, 48 + stabsize);
307  /* This seems to be okay to hardcode, since this muxer targets 1.09 features;
308  * videos produced by this muxer are readable by 1.08 and lower players. */
309  ffio_wfourcc(pb, "1.09");
310  /* I have no idea what this field does, might be reserved */
311  avio_wb32(pb, 0);
312 
313  /* Next write the FDSC (file description) chunk */
314  ffio_wfourcc(pb, "FDSC");
315  avio_wb32(pb, 0x20); /* Size of FDSC chunk */
316 
317  /* The only two supported codecs; raw video is rare */
318  switch (video->codecpar->codec_id) {
319  case AV_CODEC_ID_CINEPAK:
320  ffio_wfourcc(pb, "cvid");
321  break;
323  ffio_wfourcc(pb, "raw ");
324  break;
325  default:
326  av_log(format_context, AV_LOG_ERROR, "Incompatible video stream format.\n");
327  return AVERROR(EINVAL);
328  }
329 
330  avio_wb32(pb, video->codecpar->height);
331  avio_wb32(pb, video->codecpar->width);
332  avio_w8(pb, 24); /* Bits per pixel - observed to always be 24 */
333 
334  if (audio != NULL) {
335  avio_w8(pb, audio->codecpar->channels); /* Audio channels */
336  avio_w8(pb, audio->codecpar->bits_per_coded_sample); /* Audio bit depth */
337  avio_w8(pb, audio_codec); /* Compression - 0 is PCM, 2 is ADX */
338  avio_wb16(pb, audio->codecpar->sample_rate); /* Audio sampling rate */
339  } else {
340  /* Set all these fields to 0 if there's no audio */
341  avio_w8(pb, 0);
342  avio_w8(pb, 0);
343  avio_w8(pb, 0);
344  avio_wb16(pb, 0);
345  }
346 
347  /* I have no idea what this pair of fields does either, might be reserved */
348  avio_wb32(pb, 0);
349  avio_wb16(pb, 0);
350 
351  /* Finally, write the STAB (sample table) chunk */
352  ffio_wfourcc(pb, "STAB");
353  avio_wb32(pb, 16 + (film->packet_count * 16));
354  /* Framerate base frequency. Here we're assuming that the frame rate is even.
355  * In real world Sega FILM files, there are usually a couple of approaches:
356  * a) framerate base frequency is the same as the framerate, and ticks
357  * increment by 1 every frame, or
358  * b) framerate base frequency is a much larger number, and ticks
359  * increment by larger steps every frame.
360  * The latter occurs even in cases where the frame rate is even; for example, in
361  * Lunar: Silver Star Story, the base frequency is 600 and each frame, the ticks
362  * are incremented by 25 for an evenly spaced framerate of 24fps. */
363  avio_wb32(pb, av_q2d(av_inv_q(video->time_base)));
364 
365  avio_wb32(pb, film->packet_count);
366 
367  avio_flush(pb);
368 
369  /* Finally, write out each packet's data to the header */
370  packet = film->start;
371  while (packet != NULL) {
372  film_write_packet_to_header(format_context, packet);
373  prev = packet;
374  packet = packet->next;
375  av_freep(&prev);
376  }
377 
378  return 0;
379 }
380 
381 static const AVClass film_muxer_class = {
382  .class_name = "Sega FILM muxer",
383  .item_name = av_default_item_name,
384  .version = LIBAVUTIL_VERSION_INT,
385 };
386 
388  .name = "film_cpk",
389  .long_name = NULL_IF_CONFIG_SMALL("Sega FILM / CPK"),
390  .extensions = "cpk",
391  .priv_data_size = sizeof(FILMOutputContext),
392  .audio_codec = AV_CODEC_ID_PCM_S16BE_PLANAR,
393  .video_codec = AV_CODEC_ID_CINEPAK,
394  .init = film_init,
397  .priv_class = &film_muxer_class,
398 };
static void write_packet(OutputFile *of, AVPacket *pkt, OutputStream *ost, int unqueue)
Definition: ffmpeg.c:689
int(* io_open)(struct AVFormatContext *s, AVIOContext **pb, const char *url, int flags, AVDictionary **options)
A callback for opening new IO streams.
Definition: avformat.h:1940
#define NULL
Definition: coverity.c:32
Bytestream IO Context.
Definition: avio.h:161
int32_t index
Definition: segafilmenc.c:43
#define LIBAVUTIL_VERSION_INT
Definition: version.h:85
packed RGB 8:8:8, 24bpp, RGBRGB...
Definition: pixfmt.h:68
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
enum AVCodecID codec_id
Definition: qsv.c:72
enum AVCodecID codec_id
Specific type of the encoded data (the codec used).
Definition: avcodec.h:3953
int size
Definition: avcodec.h:1478
int64_t avio_seek(AVIOContext *s, int64_t offset, int whence)
fseek() equivalent for AVIOContext.
Definition: aviobuf.c:246
const char * av_default_item_name(void *ptr)
Return the context name.
Definition: log.c:191
#define AVIO_FLAG_READ
read-only
Definition: avio.h:654
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:236
static AVPacket pkt
Format I/O context.
Definition: avformat.h:1358
AVOutputFormat ff_segafilm_muxer
Definition: segafilmenc.c:387
const char * class_name
The name of the class; usually it is the same name as the context structure type to which the AVClass...
Definition: log.h:72
uint8_t
#define av_malloc(s)
int width
Video only.
Definition: avcodec.h:4019
int64_t duration
Duration of this packet in AVStream->time_base units, 0 if unknown.
Definition: avcodec.h:1495
void ff_format_io_close(AVFormatContext *s, AVIOContext **pb)
Definition: utils.c:5637
#define READ_BLOCK
AVStream ** streams
A list of all streams in the file.
Definition: avformat.h:1426
static const AVClass film_muxer_class
Definition: segafilmenc.c:381
uint8_t * data
Definition: avcodec.h:1477
static double av_q2d(AVRational a)
Convert an AVRational to a double.
Definition: rational.h:104
static av_always_inline int64_t avio_tell(AVIOContext *s)
ftell() equivalent for AVIOContext.
Definition: avio.h:557
void avio_write(AVIOContext *s, const unsigned char *buf, int size)
Definition: aviobuf.c:218
static av_always_inline void ffio_wfourcc(AVIOContext *pb, const uint8_t *s)
Definition: avio_internal.h:58
#define av_log(a,...)
#define AV_PKT_FLAG_KEY
The packet contains a keyframe.
Definition: avcodec.h:1509
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:260
AVCodecID
Identify the syntax and semantics of the bitstream.
Definition: avcodec.h:215
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
int32_t pts
Definition: segafilmenc.c:40
FILMPacket * last
Definition: segafilmenc.c:53
int32_t size
Definition: segafilmenc.c:42
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:186
char * url
input or output URL.
Definition: avformat.h:1454
static int film_init(AVFormatContext *format_context)
Definition: segafilmenc.c:159
enum AVMediaType codec_type
General type of the encoded data.
Definition: avcodec.h:3949
struct FILMPacket * next
Definition: segafilmenc.c:44
int flags
A combination of AV_PKT_FLAG values.
Definition: avcodec.h:1483
static int film_write_packet(AVFormatContext *format_context, AVPacket *pkt)
Definition: segafilmenc.c:85
unsigned int nb_streams
Number of elements in AVFormatContext.streams.
Definition: avformat.h:1414
int void avio_flush(AVIOContext *s)
Force flushing of buffered data.
Definition: aviobuf.c:238
static int write_trailer(AVFormatContext *s1)
Definition: v4l2enc.c:94
const char * name
Definition: avformat.h:505
static int shift_data(AVFormatContext *format_context, int64_t shift_size)
Definition: segafilmenc.c:203
int32_t
#define AV_WB24(p, d)
Definition: intreadwrite.h:450
static int film_write_header(AVFormatContext *format_context)
Definition: segafilmenc.c:260
int n
Definition: avisynth_c.h:760
Stream structure.
Definition: avformat.h:881
FILMPacket * start
Definition: segafilmenc.c:52
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_RB24
Definition: bytestream.h:87
AVIOContext * pb
I/O context.
Definition: avformat.h:1400
void avio_w8(AVIOContext *s, int b)
Definition: aviobuf.c:196
void * buf
Definition: avisynth_c.h:766
Describe the class of an AVClass context structure.
Definition: log.h:67
int32_t duration
Definition: segafilmenc.c:41
void avio_wb16(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:475
static av_always_inline AVRational av_inv_q(AVRational q)
Invert a rational.
Definition: rational.h:159
int sample_rate
Audio only.
Definition: avcodec.h:4063
Main libavformat public API header.
static int get_audio_codec_id(enum AVCodecID codec_id)
Definition: segafilmenc.c:143
int64_t packet_count
Definition: segafilmenc.c:54
A Quick Description Of Rate Distortion Theory We want to encode a video
#define av_free(p)
int keyframe
Definition: segafilmenc.c:39
void * priv_data
Format private data.
Definition: avformat.h:1386
int bits_per_coded_sample
The number of bits per sample in the codedwords.
Definition: avcodec.h:3995
int channels
Audio only.
Definition: avcodec.h:4059
void avio_wb32(AVIOContext *s, unsigned int val)
Definition: aviobuf.c:377
#define av_freep(p)
AVCodecParameters * codecpar
Codec parameters associated with this stream.
Definition: avformat.h:1028
int stream_index
Definition: avcodec.h:1479
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented...
Definition: avformat.h:910
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
This structure stores compressed data.
Definition: avcodec.h:1454
int64_t pts
Presentation timestamp in AVStream->time_base units; the time at which the decompressed packet will b...
Definition: avcodec.h:1470
static int film_write_packet_to_header(AVFormatContext *format_context, FILMPacket *pkt)
Definition: segafilmenc.c:57