* GXF muxer.
* Copyright (c) 2006 SmartJog S.A., Baptiste Coudurier <baptiste dot coudurier at smartjog dot com>.
*
- * This library is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
+ * This file is part of FFmpeg.
*
- * This library is distributed in the hope that it will be useful,
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/fifo.h"
#include "avformat.h"
#include "gxf.h"
#include "riff.h"
typedef struct GXFStreamContext {
AVCodecContext *codec;
- FifoBuffer audio_buffer;
+ AVFifoBuffer audio_buffer;
uint32_t track_type;
uint32_t sample_size;
uint32_t sample_rate;
int bframes;
int p_per_gop;
int b_per_gop;
- int closed_gop;
+ int first_gop_closed;
int64_t current_dts;
+ int dts_delay;
} GXFStreamContext;
typedef struct GXFContext {
{ 720, 6 },
};
-static const CodecTag gxf_media_types[] = {
+static const AVCodecTag gxf_media_types[] = {
{ CODEC_ID_MJPEG , 3 }, /* NTSC */
{ CODEC_ID_MJPEG , 4 }, /* PAL */
{ CODEC_ID_PCM_S24LE , 9 },
size = snprintf(buffer, 1024, "Ver 1\nBr %.6f\nIpg 1\nPpi %d\nBpiop %d\n"
"Pix 0\nCf %d\nCg %d\nSl 7\nnl16 %d\nVi 1\nf1 1\n",
(float)ctx->codec->bit_rate, ctx->p_per_gop, ctx->b_per_gop,
- ctx->codec->pix_fmt == PIX_FMT_YUV422P ? 2 : 1, ctx->closed_gop,
+ ctx->codec->pix_fmt == PIX_FMT_YUV422P ? 2 : 1, ctx->first_gop_closed == 1,
ctx->codec->height / 16);
- put_byte(pb, 0x4F);
+ put_byte(pb, TRACK_MPG_AUX);
put_byte(pb, size + 1);
put_buffer(pb, (uint8_t *)buffer, size + 1);
return size + 3;
put_be16(pb, 0); /* size */
/* media file name */
- put_byte(pb, 0x4C);
+ put_byte(pb, TRACK_NAME);
put_byte(pb, strlen(ES_NAME_PATTERN) + 3);
put_tag(pb, ES_NAME_PATTERN);
put_be16(pb, stream->media_info);
if (stream->codec->codec_id != CODEC_ID_MPEG2VIDEO) {
/* auxiliary information */
- put_byte(pb, 0x4D);
+ put_byte(pb, TRACK_AUX);
put_byte(pb, 8);
if (stream->codec->codec_id == CODEC_ID_NONE)
gxf_write_timecode_auxiliary(pb, stream);
}
/* file system version */
- put_byte(pb, 0x4E);
+ put_byte(pb, TRACK_VER);
put_byte(pb, 4);
put_be32(pb, 0);
gxf_write_mpeg_auxiliary(pb, stream);
/* frame rate */
- put_byte(pb, 0x50);
+ put_byte(pb, TRACK_FPS);
put_byte(pb, 4);
put_be32(pb, stream->frame_rate_index);
/* lines per frame */
- put_byte(pb, 0x51);
+ put_byte(pb, TRACK_LINES);
put_byte(pb, 4);
put_be32(pb, stream->lines_index);
/* fields per frame */
- put_byte(pb, 0x52);
+ put_byte(pb, TRACK_FPF);
put_byte(pb, 4);
put_be32(pb, stream->fields);
filename++;
else
filename = ctx->fc->filename;
- put_byte(pb, 0x40);
+ put_byte(pb, MAT_NAME);
put_byte(pb, strlen(SERVER_PATH) + strlen(filename) + 1);
put_tag(pb, SERVER_PATH);
put_tag(pb, filename);
put_byte(pb, 0);
/* first field */
- put_byte(pb, 0x41);
+ put_byte(pb, MAT_FIRST_FIELD);
put_byte(pb, 4);
put_be32(pb, 0);
/* last field */
- put_byte(pb, 0x42);
+ put_byte(pb, MAT_LAST_FIELD);
put_byte(pb, 4);
put_be32(pb, ctx->nb_frames);
/* reserved */
- put_byte(pb, 0x43);
+ put_byte(pb, MAT_MARK_IN);
put_byte(pb, 4);
put_be32(pb, 0);
- put_byte(pb, 0x44);
+ put_byte(pb, MAT_MARK_OUT);
put_byte(pb, 4);
put_be32(pb, ctx->nb_frames);
/* estimated size */
- put_byte(pb, 0x45);
+ put_byte(pb, MAT_SIZE);
put_byte(pb, 4);
put_be32(pb, url_fsize(pb) / 1024);
case CODEC_ID_PCM_S16LE: id= 'A'; break;
case CODEC_ID_DVVIDEO: id= sc->track_type == 6 ? 'E' : 'D'; break;
case CODEC_ID_MJPEG: id= 'V'; break;
+ default: break;
}
sc->media_info= id << 8;
/* FIXME first 10 audio tracks are 0 to 9 next 22 are A to V */
put_le32(pb, 2);
else
put_le32(pb, 1); /* default to 420 */
- put_le32(pb, stream->closed_gop); /* closed = 1, open = 0, unknown = 255 */
+ put_le32(pb, stream->first_gop_closed == 1); /* closed = 1, open = 0, unknown = 255 */
put_le32(pb, 3); /* top = 1, bottom = 2, frame = 3, unknown = 0 */
put_le32(pb, 1); /* I picture per GOP */
put_le32(pb, stream->p_per_gop);
offset_t startpos, curpos;
int path_size = strlen(ES_NAME_PATTERN);
+ memset(buffer, 0, 88);
startpos = url_ftell(pb);
put_le16(pb, 0); /* length */
put_le16(pb, sc->media_info);
return updatePacketSize(pb, pos);
}
+#define GXF_NODELAY -5000
+
static int gxf_write_header(AVFormatContext *s)
{
- ByteIOContext *pb = &s->pb;
+ ByteIOContext *pb = s->pb;
GXFContext *gxf = s->priv_data;
int i;
sc->fields = -2;
gxf->audio_tracks++;
gxf->flags |= 0x04000000; /* audio is 16 bit pcm */
- fifo_init(&sc->audio_buffer, 3*GXF_AUDIO_PACKET_SIZE);
+ av_fifo_init(&sc->audio_buffer, 3*GXF_AUDIO_PACKET_SIZE);
} else if (sc->codec->codec_type == CODEC_TYPE_VIDEO) {
/* FIXME check from time_base ? */
if (sc->codec->height == 480 || sc->codec->height == 512) { /* NTSC or NTSC+VBI */
gxf->flags |= 0x00000040;
}
gxf->sample_rate = sc->sample_rate;
- av_set_pts_info(st, 64, 1, sc->sample_rate);
+ av_set_pts_info(st, 64, 1, st->codec->time_base.den);
+ sc->dts_delay = GXF_NODELAY;
if (gxf_find_lines_index(sc) < 0)
sc->lines_index = -1;
sc->sample_size = st->codec->bit_rate;
sc->fields = 2; /* interlaced */
switch (sc->codec->codec_id) {
case CODEC_ID_MPEG2VIDEO:
+ sc->first_gop_closed = -1;
sc->track_type = 4;
gxf->mpeg_tracks++;
gxf->flags |= 0x00008000;
}
break;
default:
- av_log(NULL, AV_LOG_ERROR, "video codec not supported\n");
+ av_log(s, AV_LOG_ERROR, "video codec not supported\n");
return -1;
}
}
static int gxf_write_trailer(AVFormatContext *s)
{
- ByteIOContext *pb = &s->pb;
+ ByteIOContext *pb = s->pb;
GXFContext *gxf = s->priv_data;
offset_t end;
int i;
for (i = 0; i < s->nb_streams; ++i) {
if (s->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
- fifo_free(&gxf->streams[i].audio_buffer);
- }
- if (s->streams[i]->codec->frame_number > gxf->nb_frames)
+ av_fifo_free(&gxf->streams[i].audio_buffer);
+ } else if (s->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
gxf->nb_frames = 2 * s->streams[i]->codec->frame_number;
+ }
}
gxf_write_eos_packet(pb, gxf);
int i;
for(i=0; i<size-4 && c!=0x100; i++){
c = (c<<8) + buf[i];
- if(c == 0x1B8) /* GOP start code */
- sc->closed_gop= (buf[i+4]>>6)&1;
+ if(c == 0x1B8 && sc->first_gop_closed == -1) /* GOP start code */
+ sc->first_gop_closed= (buf[i+4]>>6)&1;
}
return (buf[i+1]>>3)&7;
}
static int gxf_write_media_preamble(ByteIOContext *pb, GXFContext *ctx, AVPacket *pkt, int size)
{
GXFStreamContext *sc = &ctx->streams[pkt->stream_index];
- int64_t dts = av_rescale(pkt->dts, ctx->sample_rate, sc->sample_rate);
+ int64_t dts = av_rescale_rnd(pkt->dts, ctx->sample_rate, sc->codec->time_base.den, AV_ROUND_UP);
put_byte(pb, sc->media_type);
put_byte(pb, sc->index);
{
GXFContext *gxf = s->priv_data;
- gxf_write_media_packet(&s->pb, gxf, pkt);
- put_flush_packet(&s->pb);
+ gxf_write_media_packet(s->pb, gxf, pkt);
+ put_flush_packet(s->pb);
return 0;
}
static int gxf_new_audio_packet(GXFContext *gxf, GXFStreamContext *sc, AVPacket *pkt, int flush)
{
- int size = flush ? fifo_size(&sc->audio_buffer, NULL) : GXF_AUDIO_PACKET_SIZE;
+ int size = flush ? av_fifo_size(&sc->audio_buffer) : GXF_AUDIO_PACKET_SIZE;
if (!size)
return 0;
av_new_packet(pkt, size);
- fifo_read(&sc->audio_buffer, pkt->data, size, NULL);
+ av_fifo_read(&sc->audio_buffer, pkt->data, size);
pkt->stream_index = sc->index;
pkt->dts = sc->current_dts;
sc->current_dts += size / 2; /* we only support 16 bit pcm mono for now */
int i;
for (i = 0; i < s->nb_streams; i++) {
- if (s->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
- GXFStreamContext *sc = &gxf->streams[i];
+ AVStream *st = s->streams[i];
+ GXFStreamContext *sc = &gxf->streams[i];
+ if (st->codec->codec_type == CODEC_TYPE_AUDIO) {
if (pkt && pkt->stream_index == i) {
- fifo_write(&sc->audio_buffer, pkt->data, pkt->size, NULL);
+ av_fifo_generic_write(&sc->audio_buffer, pkt->data, pkt->size, NULL);
pkt = NULL;
}
- if (flush || fifo_size(&sc->audio_buffer, NULL) >= GXF_AUDIO_PACKET_SIZE) {
- if (gxf_new_audio_packet(gxf, sc, &new_pkt, flush) > 0) {
+ if (flush || av_fifo_size(&sc->audio_buffer) >= GXF_AUDIO_PACKET_SIZE) {
+ if (!pkt && gxf_new_audio_packet(gxf, sc, &new_pkt, flush) > 0) {
pkt = &new_pkt;
break; /* add pkt right now into list */
}
}
+ } else if (pkt && pkt->stream_index == i) {
+ if (sc->dts_delay == GXF_NODELAY) /* adjust dts if needed */
+ sc->dts_delay = pkt->dts;
+ pkt->dts -= sc->dts_delay;
}
}
return av_interleave_packet_per_dts(s, out, pkt, flush);
AVOutputFormat gxf_muxer = {
"gxf",
- "GXF format",
+ NULL_IF_CONFIG_SMALL("GXF format"),
NULL,
"gxf",
sizeof(GXFContext),