[Avidemux-svn-commit] r3582 - in branches/avidemux_2.4_branch: . avidemux avidemux/ADM_editor avidemux/ADM_filter avidemux/ADM_libraries/ADM_lavcodec avidemux/ADM_libraries/ADM_lavformat avidemux/ADM_libraries/ADM_lavutil avidemux/ADM_outputs/oplug_mp4 avidemux/ADM_script avidemux/ADM_video
mean at BerliOS
mean at mail.berlios.de
Sat Sep 8 12:54:37 CEST 2007
Author: mean
Date: 2007-09-08 12:54:35 +0200 (Sat, 08 Sep 2007)
New Revision: 3582
Added:
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/xiph.c
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroskaenc.c
Modified:
branches/avidemux_2.4_branch/avidemux/ADM_editor/ADM_outputfmt.h
branches/avidemux_2.4_branch/avidemux/ADM_filter/filter.cpp
branches/avidemux_2.4_branch/avidemux/ADM_filter/filter_declaration.cpp
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/CMakeLists.txt
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/Makefile.am
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/utils.c
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/ADM_lavformat.cpp
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/ADM_lavformat.h
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/CMakeLists.txt
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/Makefile.am
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroska.c
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroska.h
branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavutil/crc.h
branches/avidemux_2.4_branch/avidemux/ADM_outputs/oplug_mp4/oplug_mp4.cpp
branches/avidemux_2.4_branch/avidemux/ADM_script/ADM_container.h
branches/avidemux_2.4_branch/avidemux/ADM_video/ADM_genvideo.hxx
branches/avidemux_2.4_branch/avidemux/gui_savenew.cpp
branches/avidemux_2.4_branch/config.h.cmake
branches/avidemux_2.4_branch/configure.in.in
Log:
[Output Format] Matroska output, VERY incomplete
Modified: branches/avidemux_2.4_branch/avidemux/ADM_editor/ADM_outputfmt.h
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_editor/ADM_outputfmt.h 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_editor/ADM_outputfmt.h 2007-09-08 10:54:35 UTC (rev 3582)
@@ -24,9 +24,9 @@
ADM_OGM,
ADM_PSP,
ADM_FLV,
+ ADM_MATROSKA,
ADM_DUMMY,
ADM_FORMAT_MAX,
- ADM_FMT_DUMMY=ADM_FORMAT_MAX
}ADM_OUT_FORMAT;
typedef struct
@@ -50,6 +50,7 @@
{ADM_OGM,_("OGM")},
{ADM_PSP,_("PSP")},
{ADM_FLV,_("FLV")},
+ {ADM_MATROSKA,_("MKV")},
{ADM_DUMMY,_("DUMMY")}
};
Modified: branches/avidemux_2.4_branch/avidemux/ADM_filter/filter.cpp
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_filter/filter.cpp 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_filter/filter.cpp 2007-09-08 10:54:35 UTC (rev 3582)
@@ -100,7 +100,7 @@
for(uint32_t i=0;i<allfilters.size();i++)
{
name=allfilters[ i].filtername;
- if(allfilters[ i].viewable)
+ if(allfilters[ i].viewable || allfilters[i].tag==VF_PARTIAL)
{
if(name)
{
@@ -323,55 +323,106 @@
{
int found,l;
int trans[MAXPARAM];
- if(nb!=param->nb)
+ if(param->nb>VARIABLE_PARAMS)
{
- printf("# of parameters mismatch\n");
- return NULL;
+ // Variable # of parameters
+ // We check we have at least what is required by the template
+ for(int i=0;i<(param->nb-VARIABLE_PARAMS);i++)
+ {
+ l=strlen(param->param[i]);
+ ADM_assert(l);
+ found=-1;
+ for(int j=0;j<nb;j++)
+ {
+ if(!strncasecmp(param->param[i],args[j].arg.string,l))
+ {
+ if(strlen(args[j].arg.string)>l && args[j].arg.string[l]=='=')
+ {
+ found=j;
+ break;
+ }
+ }
+ }
+ if(found==-1)
+ {
+ printf("Param : %s not found or incorrect\n",param->param[i]);
+ return NULL;
+ }
+ }
+ // if we get here, it means we found each param, time to build the couples
+ CONFcouple *couple;
+ couple=new CONFcouple(nb);
+ for(int i=0;i<nb;i++)
+ {
+ char *copy=ADM_strdup(args[i].arg.string);
+ // Search "="
+ char *where=strstr(copy,"=");
+ if(!where) ADM_assert(0);
+ *where=0;
+ if(!couple->setCouple(copy,where+1))
+ {
+ printf("Set couple failed\n");
+ delete couple;
+ return NULL;
+ }
+ ADM_dealloc(copy);
+ }
+ return couple;
}
- // For each param check we are ok
- // the generic form is name=value
- // name should be the same as in the param array
- for(int i=0;i<nb;i++)
+ //********************* Constant # of parameters #################
+ else
{
- l=strlen(param->param[i]);
- ADM_assert(l);
- found=-1;
- for(int j=0;j<nb;j++)
+ if(nb!=param->nb )
{
- if(!strncasecmp(param->param[i],args[j].arg.string,l))
+ printf("# of parameters mismatch: expected %d, got %d\n",nb,param->nb);
+ return NULL;
+ }
+ // For each param check we are ok
+ // the generic form is name=value
+ // name should be the same as in the param array
+ for(int i=0;i<nb;i++)
+ {
+ l=strlen(param->param[i]);
+ ADM_assert(l);
+ found=-1;
+ for(int j=0;j<nb;j++)
{
- if(strlen(args[j].arg.string)>l && args[j].arg.string[l]=='=')
+ if(!strncasecmp(param->param[i],args[j].arg.string,l))
{
- found=j;
- trans[i]=j;
- break;
+ if(strlen(args[j].arg.string)>l && args[j].arg.string[l]=='=')
+ {
+ found=j;
+ trans[i]=j;
+ break;
+ }
}
}
+ if(found==-1)
+ {
+ printf("Param : %s not found or incorrect\n",param->param[i]);
+ return NULL;
+ }
}
- if(found==-1)
- {
- printf("Param : %s not found or incorrect\n",param->param[i]);
- return NULL;
+ // if we get here, it means we found each param, time to build the couples
+ CONFcouple *couple;
+ couple=new CONFcouple(nb);
+ for(int i=0;i<nb;i++)
+ {
+ l=strlen(param->param[i]);
+ if(!couple->setCouple(param->param[i],args[ trans[i]].arg.string+l+1))
+ {
+ printf("Set couple failed\n");
+ delete couple;
+ return NULL;
+ }
}
+ return couple;
}
- // if we get here, it means we found each param, time to build the couples
- CONFcouple *couple;
- couple=new CONFcouple(nb);
- for(int i=0;i<nb;i++)
- {
- l=strlen(param->param[i]);
- if(!couple->setCouple(param->param[i],args[ trans[i]].arg.string+l+1))
- {
- printf("Set couple failed\n");
- delete couple;
- return NULL;
- }
- }
- return couple;
+
}
uint8_t filterAddScript(VF_FILTERS tag,uint32_t n,Arg *args)
{
- // 1- searc filter
+ // 1- search filter
int found=-1;
aviInfo info;
@@ -403,7 +454,7 @@
return 1;
}
}
- printf("Tag not found\n");
+ printf("Tag not found:%d\n",tag);
return 0;
}
Modified: branches/avidemux_2.4_branch/avidemux/ADM_filter/filter_declaration.cpp
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_filter/filter_declaration.cpp 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_filter/filter_declaration.cpp 2007-09-08 10:54:35 UTC (rev 3582)
@@ -177,7 +177,7 @@
// Does not work
// REGISTERX("unblend","Unblend by Bach",VF_UNBLEND,1,unblend_create,unblend_script);
- REGISTER("","Partial","",VF_PARTIAL,0,partial_create);
+ REGISTERX("partial","Partial","",VF_PARTIAL,0,partial_create,partial_script);
// REGISTER("","Remove Salt",VF_SALT,0,salt_create);
printf("\n");
}
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/CMakeLists.txt
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/CMakeLists.txt 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/CMakeLists.txt 2007-09-08 10:54:35 UTC (rev 3582)
@@ -30,7 +30,7 @@
wma.c
dvbsub_parser.c
dvbsubdec.c
- dvbsub.c
+ dvbsub.c xiph.c
)
# ADD x86 ones
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/Makefile.am
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/Makefile.am 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/Makefile.am 2007-09-08 10:54:35 UTC (rev 3582)
@@ -69,7 +69,7 @@
wma.c \
dvbsub_parser.c \
dvbsubdec.c \
- dvbsub.c
+ dvbsub.c xiph.c
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/utils.c
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/utils.c 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/utils.c 2007-09-08 10:54:35 UTC (rev 3582)
@@ -147,6 +147,8 @@
uint8_t *base[4];
uint8_t *data[4];
int linesize[4];
+ int width, height;
+ enum PixelFormat pix_fmt;
}InternalBuffer;
#define INTERNAL_BUFFER_SIZE 32
@@ -251,6 +253,13 @@
picture_number= &(((InternalBuffer*)s->internal_buffer)[INTERNAL_BUFFER_SIZE-1]).last_pic_num; //FIXME ugly hack
(*picture_number)++;
+ if(buf->base[0] && (buf->width != w || buf->height != h || buf->pix_fmt != s->pix_fmt)){
+ for(i=0; i<4; i++){
+ av_freep(&buf->base[i]);
+ buf->data[i]= NULL;
+ }
+ }
+
if(buf->base[0]){
pic->age= *picture_number - buf->last_pic_num;
buf->last_pic_num= *picture_number;
@@ -306,6 +315,9 @@
else
buf->data[i] = buf->base[i] + ALIGN((buf->linesize[i]*EDGE_WIDTH>>v_shift) + (EDGE_WIDTH>>h_shift), STRIDE_ALIGN);
}
+ buf->width = s->width;
+ buf->height = s->height;
+ buf->pix_fmt= s->pix_fmt;
pic->age= 256*256*256*64;
}
pic->type= FF_BUFFER_TYPE_INTERNAL;
@@ -741,6 +753,7 @@
{"timecode_frame_start", "GOP timecode frame start number, in non drop frame format", OFFSET(timecode_frame_start), FF_OPT_TYPE_INT, 0, 0, INT_MAX, V|E},
{"drop_frame_timecode", NULL, 0, FF_OPT_TYPE_CONST, CODEC_FLAG2_DROP_FRAME_TIMECODE, INT_MIN, INT_MAX, V|E, "flags2"},
{"non_linear_q", "use non linear quantizer", 0, FF_OPT_TYPE_CONST, CODEC_FLAG2_NON_LINEAR_QUANT, INT_MIN, INT_MAX, V|E, "flags2"},
+// MEANX {"request_channels", "set desired number of audio channels", OFFSET(request_channels), FF_OPT_TYPE_INT, DEFAULT, 0, INT_MAX, A|D},
{NULL},
};
@@ -759,6 +772,7 @@
s->av_class= &av_codec_context_class;
+ s->codec_type = codec_type;
if(codec_type == CODEC_TYPE_AUDIO)
flags= AV_OPT_FLAG_AUDIO_PARAM;
else if(codec_type == CODEC_TYPE_VIDEO)
@@ -831,8 +845,10 @@
if (codec->priv_data_size > 0) {
avctx->priv_data = av_mallocz(codec->priv_data_size);
- if (!avctx->priv_data)
+ if (!avctx->priv_data) {
+ ret = AVERROR(ENOMEM);
goto end;
+ }
} else {
avctx->priv_data = NULL;
}
@@ -844,6 +860,7 @@
if((avctx->coded_width||avctx->coded_height) && avcodec_check_dimensions(avctx,avctx->coded_width,avctx->coded_height)){
av_freep(&avctx->priv_data);
+ ret = AVERROR(EINVAL);
goto end;
}
@@ -938,7 +955,7 @@
if((avctx->codec->capabilities & CODEC_CAP_DELAY) || buf_size){
//FIXME remove the check below _after_ ensuring that all audio check that the available space is enough
-#if 0 // MEANX SILENCE!
+#if 0 // MEANX : Silence
if(*frame_size_ptr < AVCODEC_MAX_AUDIO_FRAME_SIZE){
av_log(avctx, AV_LOG_ERROR, "buffer smaller than AVCODEC_MAX_AUDIO_FRAME_SIZE\n");
return -1;
@@ -1221,9 +1238,9 @@
av_crc8005 = av_mallocz_static(sizeof(AVCRC) * 257);
av_crc07 = av_mallocz_static(sizeof(AVCRC) * 257);
#endif
- av_crc_init(av_crc04C11DB7, 0, 32, 0x04c11db7, sizeof(AVCRC)*257);
- av_crc_init(av_crc8005 , 0, 16, 0x8005 , sizeof(AVCRC)*257);
- av_crc_init(av_crc07 , 0, 8, 0x07 , sizeof(AVCRC)*257);
+ av_crc_init(av_crc04C11DB7, 0, 32, AV_CRC_32_IEEE, sizeof(AVCRC)*257);
+ av_crc_init(av_crc8005 , 0, 16, AV_CRC_16 , sizeof(AVCRC)*257);
+ av_crc_init(av_crc07 , 0, 8, AV_CRC_8_ATM , sizeof(AVCRC)*257);
}
void avcodec_init(void)
@@ -1308,6 +1325,22 @@
}
}
+int av_get_bits_per_sample_format(enum SampleFormat sample_fmt) {
+ switch (sample_fmt) {
+ case SAMPLE_FMT_U8:
+ return 8;
+ case SAMPLE_FMT_S16:
+ return 16;
+ case SAMPLE_FMT_S24:
+ return 24;
+ case SAMPLE_FMT_S32:
+ case SAMPLE_FMT_FLT:
+ return 32;
+ default:
+ return 0;
+ }
+}
+
#if !defined(HAVE_THREADS)
int avcodec_thread_init(AVCodecContext *s, int thread_count){
return -1;
@@ -1347,7 +1380,7 @@
return -1;
}
#if !defined(HAVE_MKSTEMP)
- fd = open(*filename, O_RDWR | /* MEANX ??O_BINARY |*/ O_CREAT, 0444);
+ fd = open(*filename, O_RDWR /* MEANX | O_BINARY*/ | O_CREAT, 0444);
#else
snprintf(*filename, len, "/tmp/%sXXXXXX", prefix);
fd = mkstemp(*filename);
Added: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/xiph.c
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/xiph.c 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavcodec/xiph.c 2007-09-08 10:54:35 UTC (rev 3582)
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 FFmpeg Project
+ *
+ * This file is part of FFmpeg.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * 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 "xiph.h"
+
+int ff_split_xiph_headers(uint8_t *extradata, int extradata_size,
+ int first_header_size, uint8_t *header_start[3],
+ int header_len[3])
+{
+ int i, j;
+
+ if (AV_RB16(extradata) == first_header_size) {
+ for (i=0; i<3; i++) {
+ header_len[i] = AV_RB16(extradata);
+ extradata += 2;
+ header_start[i] = extradata;
+ extradata += header_len[i];
+ }
+ } else if (extradata[0] == 2) {
+ for (i=0,j=1; i<2; i++,j++) {
+ header_len[i] = 0;
+ for (; j<extradata_size && extradata[j]==0xff; j++) {
+ header_len[i] += 0xff;
+ }
+ if (j >= extradata_size)
+ return -1;
+
+ header_len[i] += extradata[j];
+ }
+ header_len[2] = extradata_size - header_len[0] - header_len[1] - j;
+ extradata += j;
+ header_start[0] = extradata;
+ header_start[1] = header_start[0] + header_len[0];
+ header_start[2] = header_start[1] + header_len[1];
+ } else {
+ return -1;
+ }
+ return 0;
+}
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/ADM_lavformat.cpp
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/ADM_lavformat.cpp 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/ADM_lavformat.cpp 2007-09-08 10:54:35 UTC (rev 3582)
@@ -130,12 +130,17 @@
case MUXER_FLV:
fmt = guess_format("flv", NULL, NULL);
break;
+ case MUXER_MATROSKA:
+ fmt = guess_format("matroska", NULL, NULL);
+ break;
+
default:
fmt=NULL;
}
if (!fmt)
{
printf("Lav:Cannot guess format\n");
+ ADM_assert(0);
return 0;
}
oc = av_alloc_format_context();
@@ -179,6 +184,32 @@
}
break;
+ case MUXER_MATROSKA:
+ strcpy(oc->title,"Avidemux");
+ strcpy(oc->author,"Avidemux");
+ c->sample_aspect_ratio.num=1;
+ c->sample_aspect_ratio.den=1;
+ if(isMpeg4Compatible(info->fcc))
+ {
+ c->codec_id = CODEC_ID_MPEG4;
+ c->has_b_frames=1; // in doubt...
+ }else
+ {
+ if(isH264Compatible(info->fcc))
+ {
+ c->has_b_frames=1; // in doubt...
+ c->codec_id = CODEC_ID_H264;
+ c->codec=new AVCodec;
+ memset(c->codec,0,sizeof(AVCodec));
+ c->codec->name=ADM_strdup("H264");
+ }
+ }
+ if(videoExtraDataSize)
+ {
+ c->extradata=videoExtraData;
+ c->extradata_size= videoExtraDataSize;
+ }
+ break;
case MUXER_MP4:
case MUXER_PSP:
strcpy(oc->title,"Avidemux");
@@ -321,7 +352,7 @@
break;
default:
{
- if(_type==MUXER_MP4 || _type==MUXER_PSP || _type==MUXER_FLV)
+ if(_type==MUXER_MP4 || _type==MUXER_PSP || _type==MUXER_FLV || _type==MUXER_MATROSKA)
{
c->time_base=fpsfree;// (AVRational){1000,_fps1000};
break;
@@ -407,6 +438,7 @@
case MUXER_FLV:
case MUXER_PSP:
case MUXER_MP4:
+ case MUXER_MATROSKA:
oc->mux_rate=10080*1000; // Needed ?
break;
@@ -473,7 +505,7 @@
timeInUs=(int64_t)sample2time_us(sample);
/* Rescale to ?? */
- if(_type==MUXER_FLV) /* The FLV muxer expects packets dated in ms, there is something i did not get... WTF */
+ if(_type==MUXER_FLV || _type==MUXER_MATROSKA) /* The FLV muxer expects packets dated in ms, there is something i did not get... WTF */
{
f=timeInUs/1000;
f=floor(f+0.4);
@@ -567,7 +599,7 @@
d=bitstream->dtsFrame;
RESCALE(d);
- if(_type==MUXER_FLV) /* The FLV muxer expects packets dated in ms, there is something i did not get... WTF */
+ if(_type==MUXER_FLV || _type==MUXER_MATROSKA) /* The FLV muxer expects packets dated in ms, there is something i did not get... WTF */
{
p=p*1000/_fps1000;
d=d*1000/_fps1000;
@@ -646,12 +678,14 @@
extern int mpegps_init(void );
extern int movenc_init(void );
extern int flvenc_init(void );
+ extern int matroskaenc_init(void );
};
extern URLProtocol file_protocol ;
uint8_t lavformat_init(void)
{
movenc_init();
flvenc_init();
+ matroskaenc_init();
register_protocol(&file_protocol);
}
extern "C"
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/ADM_lavformat.h
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/ADM_lavformat.h 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/ADM_lavformat.h 2007-09-08 10:54:35 UTC (rev 3582)
@@ -24,6 +24,7 @@
MUXER_MP4,
MUXER_PSP,
MUXER_FLV,
+ MUXER_MATROSKA,
MUXER_DUMMY
}ADM_MUXER_TYPE;
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/CMakeLists.txt
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/CMakeLists.txt 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/CMakeLists.txt 2007-09-08 10:54:35 UTC (rev 3582)
@@ -8,7 +8,7 @@
mpeg.c utils.c avio.c ADM_lavformat.cpp
aviobuf.c cutils.c img2.c file.c mpegtsenc.c ADM_muxts.cpp movenc.c
avienc.c wav.c mov.c matroska.c isom.c isom.h riff.c
-flvenc.c
+flvenc.c matroskaenc.c
)
ADD_LIBRARY(${ADM_LIB} STATIC ${${ADM_LIB}_SRCS})
ADD_ADM_LIB(${ADM_LIB} ADM_libraries)
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/Makefile.am
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/Makefile.am 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/Makefile.am 2007-09-08 10:54:35 UTC (rev 3582)
@@ -6,7 +6,8 @@
libADM_lavformat_a_SOURCES = mpeg.c utils.c avio.c ADM_lavformat.cpp \
aviobuf.c cutils.c img2.c file.c mpegtsenc.c ADM_muxts.cpp movenc.c \
-avienc.c wav.c mov.c matroska.c isom.c isom.h riff.c flvenc.c
+avienc.c wav.c mov.c matroska.c isom.c isom.h riff.c flvenc.c \
+matroskaenc.c
EXTRA_DIST = ADM_lavformat.cpp ADM_muxts.cpp avformat.h avio.h \
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroska.c
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroska.c 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroska.c 2007-09-08 10:54:35 UTC (rev 3582)
@@ -24,8 +24,8 @@
CodecTags ff_mkv_codec_tags[]={
// {"V_MS/VFW/FOURCC" , CODEC_ID_NONE},
{"V_UNCOMPRESSED" , CODEC_ID_RAWVIDEO},
+ {"V_MPEG4/ISO/ASP" , CODEC_ID_MPEG4},
{"V_MPEG4/ISO/SP" , CODEC_ID_MPEG4},
- {"V_MPEG4/ISO/ASP" , CODEC_ID_MPEG4},
{"V_MPEG4/ISO/AP" , CODEC_ID_MPEG4},
{"V_MPEG4/ISO/AVC" , CODEC_ID_H264},
{"V_MPEG4/MS/V3" , CODEC_ID_MSMPEG4V3},
@@ -37,12 +37,13 @@
{"V_REAL/RV30" , CODEC_ID_RV30},
{"V_REAL/RV40" , CODEC_ID_RV40},
{"V_THEORA" , CODEC_ID_THEORA},
+ {"V_SNOW" , CODEC_ID_SNOW},
/* TODO: Real/Quicktime */
// {"A_MS/ACM" , CODEC_ID_NONE},
- {"A_MPEG/L1" , CODEC_ID_MP3},
- {"A_MPEG/L2" , CODEC_ID_MP3},
{"A_MPEG/L3" , CODEC_ID_MP3},
+ {"A_MPEG/L2" , CODEC_ID_MP2},
+ {"A_MPEG/L1" , CODEC_ID_MP2},
{"A_PCM/INT/BIG" , CODEC_ID_PCM_U16BE},
{"A_PCM/INT/LIT" , CODEC_ID_PCM_U16LE},
// {"A_PCM/FLOAT/IEEE" , CODEC_ID_NONE},
@@ -59,10 +60,12 @@
{"A_REAL/COOK" , CODEC_ID_COOK},
// {"A_REAL/SIPR" , CODEC_ID_SIPRO},
+ {"S_TEXT/UTF8" , CODEC_ID_TEXT},
{"S_TEXT/ASCII" , CODEC_ID_TEXT},
- {"S_TEXT/UTF8" , CODEC_ID_TEXT},
{"S_TEXT/ASS" , CODEC_ID_TEXT},
{"S_TEXT/SSA" , CODEC_ID_TEXT},
+ {"S_ASS" , CODEC_ID_TEXT},
+ {"S_SSA" , CODEC_ID_TEXT},
{"S_VOBSUB" , CODEC_ID_DVD_SUBTITLE},
{NULL , CODEC_ID_NONE}
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroska.h
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroska.h 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroska.h 2007-09-08 10:54:35 UTC (rev 3582)
@@ -64,6 +64,7 @@
#define MATROSKA_ID_WRITINGAPP 0x5741
#define MATROSKA_ID_MUXINGAPP 0x4D80
#define MATROSKA_ID_DATEUTC 0x4461
+#define MATROSKA_ID_SEGMENTUID 0x73A4
/* ID in the tracks master */
#define MATROSKA_ID_TRACKENTRY 0xAE
Added: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroskaenc.c
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroskaenc.c 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavformat/matroskaenc.c 2007-09-08 10:54:35 UTC (rev 3582)
@@ -0,0 +1,836 @@
+/*
+ * Matroska muxer
+ * Copyright (c) 2007 David Conrad
+ *
+ * This file is part of FFmpeg.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * 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 "avformat.h"
+#include "md5.h"
+#include "riff.h"
+#include "xiph.h"
+#include "matroska.h"
+
+typedef struct ebml_master {
+ offset_t pos; ///< absolute offset in the file where the master's elements start
+ int sizebytes; ///< how many bytes were reserved for the size
+} ebml_master;
+
+typedef struct mkv_seekhead_entry {
+ unsigned int elementid;
+ uint64_t segmentpos;
+} mkv_seekhead_entry;
+
+typedef struct mkv_seekhead {
+ offset_t filepos;
+ offset_t segment_offset; ///< the file offset to the beginning of the segment
+ int reserved_size; ///< -1 if appending to file
+ int max_entries;
+ mkv_seekhead_entry *entries;
+ int num_entries;
+} mkv_seekhead;
+
+typedef struct {
+ uint64_t pts;
+ int tracknum;
+ offset_t cluster_pos; ///< file offset of the cluster containing the block
+} mkv_cuepoint;
+
+typedef struct {
+ offset_t segment_offset;
+ mkv_cuepoint *entries;
+ int num_entries;
+} mkv_cues;
+
+typedef struct MatroskaMuxContext {
+ ebml_master segment;
+ offset_t segment_offset;
+ offset_t segment_uid;
+ ebml_master cluster;
+ offset_t cluster_pos; ///< file offset of the current cluster
+ uint64_t cluster_pts;
+ offset_t duration_offset;
+ uint64_t duration;
+ mkv_seekhead *main_seekhead;
+ mkv_seekhead *cluster_seekhead;
+ mkv_cues *cues;
+
+ struct AVMD5 *md5_ctx;
+} MatroskaMuxContext;
+
+
+/** 2 bytes * 3 for EBML IDs, 3 1-byte EBML lengths, 8 bytes for 64 bit
+ * offset, 4 bytes for target EBML ID */
+#define MAX_SEEKENTRY_SIZE 21
+
+/** per-cuepoint-track - 3 1-byte EBML IDs, 3 1-byte EBML sizes, 2
+ * 8-byte uint max */
+#define MAX_CUETRACKPOS_SIZE 22
+
+/** per-cuepoint - 2 1-byte EBML IDs, 2 1-byte EBML sizes, 8-byte uint max */
+#define MAX_CUEPOINT_SIZE(num_tracks) 12 + MAX_CUETRACKPOS_SIZE*num_tracks
+
+
+static int ebml_id_size(unsigned int id)
+{
+ return (av_log2(id+1)-1)/7+1;
+}
+
+static void put_ebml_id(ByteIOContext *pb, unsigned int id)
+{
+ int i = ebml_id_size(id);
+ while (i--)
+ put_byte(pb, id >> (i*8));
+}
+
+/**
+ * Write an EBML size meaning "unknown size".
+ *
+ * @param bytes The number of bytes the size should occupy (maximum: 8).
+ */
+static void put_ebml_size_unknown(ByteIOContext *pb, int bytes)
+{
+ assert(bytes <= 8);
+ put_byte(pb, 0x1ff >> bytes);
+ while (--bytes)
+ put_byte(pb, 0xff);
+}
+
+/**
+ * Calculate how many bytes are needed to represent a given number in EBML.
+ */
+static int ebml_num_size(uint64_t num)
+{
+ int bytes = 1;
+ while ((num+1) >> bytes*7) bytes++;
+ return bytes;
+}
+
+/**
+ * Write a number in EBML variable length format.
+ *
+ * @param bytes The number of bytes that need to be used to write the number.
+ * If zero, any number of bytes can be used.
+ */
+static void put_ebml_num(ByteIOContext *pb, uint64_t num, int bytes)
+{
+ int i, needed_bytes = ebml_num_size(num);
+
+ // sizes larger than this are currently undefined in EBML
+ assert(num < (1ULL<<56)-1);
+
+ if (bytes == 0)
+ // don't care how many bytes are used, so use the min
+ bytes = needed_bytes;
+ // the bytes needed to write the given size would exceed the bytes
+ // that we need to use, so write unknown size. This shouldn't happen.
+ assert(bytes >= needed_bytes);
+
+ num |= 1ULL << bytes*7;
+ for (i = bytes - 1; i >= 0; i--)
+ put_byte(pb, num >> i*8);
+}
+
+static void put_ebml_uint(ByteIOContext *pb, unsigned int elementid, uint64_t val)
+{
+ int i, bytes = 1;
+ while (val >> bytes*8) bytes++;
+
+ put_ebml_id(pb, elementid);
+ put_ebml_num(pb, bytes, 0);
+ for (i = bytes - 1; i >= 0; i--)
+ put_byte(pb, val >> i*8);
+}
+
+static void put_ebml_float(ByteIOContext *pb, unsigned int elementid, double val)
+{
+ put_ebml_id(pb, elementid);
+ put_ebml_num(pb, 8, 0);
+ put_be64(pb, av_dbl2int(val));
+}
+
+static void put_ebml_binary(ByteIOContext *pb, unsigned int elementid,
+ const uint8_t *buf, int size)
+{
+ put_ebml_id(pb, elementid);
+ put_ebml_num(pb, size, 0);
+ put_buffer(pb, buf, size);
+}
+
+static void put_ebml_string(ByteIOContext *pb, unsigned int elementid, const char *str)
+{
+ put_ebml_binary(pb, elementid, str, strlen(str));
+}
+
+/**
+ * Writes a void element of a given size. Useful for reserving space in
+ * the file to be written to later.
+ *
+ * @param size The number of bytes to reserve, which must be at least 2.
+ */
+static void put_ebml_void(ByteIOContext *pb, uint64_t size)
+{
+ offset_t currentpos = url_ftell(pb);
+
+ assert(size >= 2);
+
+ put_ebml_id(pb, EBML_ID_VOID);
+ // we need to subtract the length needed to store the size from the
+ // size we need to reserve so 2 cases, we use 8 bytes to store the
+ // size if possible, 1 byte otherwise
+ if (size < 10)
+ put_ebml_num(pb, size-1, 0);
+ else
+ put_ebml_num(pb, size-9, 8);
+ url_fseek(pb, currentpos + size, SEEK_SET);
+}
+
+static ebml_master start_ebml_master(ByteIOContext *pb, unsigned int elementid, uint64_t expectedsize)
+{
+ int bytes = expectedsize ? ebml_num_size(expectedsize) : 8;
+ put_ebml_id(pb, elementid);
+ put_ebml_size_unknown(pb, bytes);
+ return (ebml_master){ url_ftell(pb), bytes };
+}
+
+static void end_ebml_master(ByteIOContext *pb, ebml_master master)
+{
+ offset_t pos = url_ftell(pb);
+
+ // leave the unknown size for masters when streaming
+ if (url_is_streamed(pb))
+ return;
+
+ url_fseek(pb, master.pos - master.sizebytes, SEEK_SET);
+ put_ebml_num(pb, pos - master.pos, master.sizebytes);
+ url_fseek(pb, pos, SEEK_SET);
+}
+
+static void put_xiph_size(ByteIOContext *pb, int size)
+{
+ int i;
+ for (i = 0; i < size / 255; i++)
+ put_byte(pb, 255);
+ put_byte(pb, size % 255);
+}
+
+/**
+ * Initialize a mkv_seekhead element to be ready to index level 1 Matroska
+ * elements. If a maximum number of elements is specified, enough space
+ * will be reserved at the current file location to write a seek head of
+ * that size.
+ *
+ * @param segment_offset The absolute offset to the position in the file
+ * where the segment begins.
+ * @param numelements The maximum number of elements that will be indexed
+ * by this seek head, 0 if unlimited.
+ */
+static mkv_seekhead * mkv_start_seekhead(ByteIOContext *pb, offset_t segment_offset, int numelements)
+{
+ mkv_seekhead *new_seekhead = av_mallocz(sizeof(mkv_seekhead));
+ if (new_seekhead == NULL)
+ return NULL;
+
+ new_seekhead->segment_offset = segment_offset;
+
+ if (numelements > 0) {
+ new_seekhead->filepos = url_ftell(pb);
+ // 21 bytes max for a seek entry, 10 bytes max for the SeekHead ID
+ // and size, and 3 bytes to guarantee that an EBML void element
+ // will fit afterwards
+ new_seekhead->reserved_size = numelements * MAX_SEEKENTRY_SIZE + 13;
+ new_seekhead->max_entries = numelements;
+ put_ebml_void(pb, new_seekhead->reserved_size);
+ }
+ return new_seekhead;
+}
+
+static int mkv_add_seekhead_entry(mkv_seekhead *seekhead, unsigned int elementid, uint64_t filepos)
+{
+ mkv_seekhead_entry *entries = seekhead->entries;
+
+ // don't store more elements than we reserved space for
+ if (seekhead->max_entries > 0 && seekhead->max_entries <= seekhead->num_entries)
+ return -1;
+
+ entries = av_realloc(entries, (seekhead->num_entries + 1) * sizeof(mkv_seekhead_entry));
+ if (entries == NULL)
+ return AVERROR(ENOMEM);
+
+ entries[seekhead->num_entries ].elementid = elementid;
+ entries[seekhead->num_entries++].segmentpos = filepos - seekhead->segment_offset;
+
+ seekhead->entries = entries;
+ return 0;
+}
+
+/**
+ * Write the seek head to the file and free it. If a maximum number of
+ * elements was specified to mkv_start_seekhead(), the seek head will
+ * be written at the location reserved for it. Otherwise, it is written
+ * at the current location in the file.
+ *
+ * @return The file offset where the seekhead was written.
+ */
+static offset_t mkv_write_seekhead(ByteIOContext *pb, mkv_seekhead *seekhead)
+{
+ ebml_master metaseek, seekentry;
+ offset_t currentpos;
+ int i;
+
+ currentpos = url_ftell(pb);
+
+ if (seekhead->reserved_size > 0)
+ url_fseek(pb, seekhead->filepos, SEEK_SET);
+
+ metaseek = start_ebml_master(pb, MATROSKA_ID_SEEKHEAD, seekhead->reserved_size);
+ for (i = 0; i < seekhead->num_entries; i++) {
+ mkv_seekhead_entry *entry = &seekhead->entries[i];
+
+ seekentry = start_ebml_master(pb, MATROSKA_ID_SEEKENTRY, MAX_SEEKENTRY_SIZE);
+
+ put_ebml_id(pb, MATROSKA_ID_SEEKID);
+ put_ebml_num(pb, ebml_id_size(entry->elementid), 0);
+ put_ebml_id(pb, entry->elementid);
+
+ put_ebml_uint(pb, MATROSKA_ID_SEEKPOSITION, entry->segmentpos);
+ end_ebml_master(pb, seekentry);
+ }
+ end_ebml_master(pb, metaseek);
+
+ if (seekhead->reserved_size > 0) {
+ uint64_t remaining = seekhead->filepos + seekhead->reserved_size - url_ftell(pb);
+ put_ebml_void(pb, remaining);
+ url_fseek(pb, currentpos, SEEK_SET);
+
+ currentpos = seekhead->filepos;
+ }
+ av_free(seekhead->entries);
+ av_free(seekhead);
+
+ return currentpos;
+}
+
+static mkv_cues * mkv_start_cues(offset_t segment_offset)
+{
+ mkv_cues *cues = av_mallocz(sizeof(mkv_cues));
+ if (cues == NULL)
+ return NULL;
+
+ cues->segment_offset = segment_offset;
+ return cues;
+}
+
+static int mkv_add_cuepoint(mkv_cues *cues, AVPacket *pkt, offset_t cluster_pos)
+{
+ mkv_cuepoint *entries = cues->entries;
+
+ entries = av_realloc(entries, (cues->num_entries + 1) * sizeof(mkv_cuepoint));
+ if (entries == NULL)
+ return AVERROR(ENOMEM);
+
+ entries[cues->num_entries ].pts = pkt->pts;
+ entries[cues->num_entries ].tracknum = pkt->stream_index + 1;
+ entries[cues->num_entries++].cluster_pos = cluster_pos - cues->segment_offset;
+
+ cues->entries = entries;
+ return 0;
+}
+
+static offset_t mkv_write_cues(ByteIOContext *pb, mkv_cues *cues, int num_tracks)
+{
+ ebml_master cues_element;
+ offset_t currentpos;
+ int i, j;
+
+ currentpos = url_ftell(pb);
+ cues_element = start_ebml_master(pb, MATROSKA_ID_CUES, 0);
+
+ for (i = 0; i < cues->num_entries; i++) {
+ ebml_master cuepoint, track_positions;
+ mkv_cuepoint *entry = &cues->entries[i];
+ uint64_t pts = entry->pts;
+
+ cuepoint = start_ebml_master(pb, MATROSKA_ID_POINTENTRY, MAX_CUEPOINT_SIZE(num_tracks));
+ put_ebml_uint(pb, MATROSKA_ID_CUETIME, pts);
+
+ // put all the entries from different tracks that have the exact same
+ // timestamp into the same CuePoint
+ for (j = 0; j < cues->num_entries - i && entry[j].pts == pts; j++) {
+ track_positions = start_ebml_master(pb, MATROSKA_ID_CUETRACKPOSITION, MAX_CUETRACKPOS_SIZE);
+ put_ebml_uint(pb, MATROSKA_ID_CUETRACK , entry[j].tracknum );
+ put_ebml_uint(pb, MATROSKA_ID_CUECLUSTERPOSITION, entry[j].cluster_pos);
+ end_ebml_master(pb, track_positions);
+ }
+ i += j - 1;
+ end_ebml_master(pb, cuepoint);
+ }
+ end_ebml_master(pb, cues_element);
+
+ av_free(cues->entries);
+ av_free(cues);
+ return currentpos;
+}
+
+static int put_xiph_codecpriv(AVFormatContext *s, ByteIOContext *pb, AVCodecContext *codec)
+{
+ uint8_t *header_start[3];
+ int header_len[3];
+ int first_header_size;
+ int j;
+
+ if (codec->codec_id == CODEC_ID_VORBIS)
+ first_header_size = 30;
+ else
+ first_header_size = 42;
+
+ if (ff_split_xiph_headers(codec->extradata, codec->extradata_size,
+ first_header_size, header_start, header_len) < 0) {
+ av_log(s, AV_LOG_ERROR, "Extradata corrupt.\n");
+ return -1;
+ }
+
+ put_byte(pb, 2); // number packets - 1
+ for (j = 0; j < 2; j++) {
+ put_xiph_size(pb, header_len[j]);
+ }
+ for (j = 0; j < 3; j++)
+ put_buffer(pb, header_start[j], header_len[j]);
+
+ return 0;
+}
+
+#define FLAC_STREAMINFO_SIZE 34
+
+static int put_flac_codecpriv(AVFormatContext *s, ByteIOContext *pb, AVCodecContext *codec)
+{
+ // if the extradata_size is greater than FLAC_STREAMINFO_SIZE,
+ // assume that it's in Matroska's format already
+ if (codec->extradata_size < FLAC_STREAMINFO_SIZE) {
+ av_log(s, AV_LOG_ERROR, "Invalid FLAC extradata\n");
+ return -1;
+ } else if (codec->extradata_size == FLAC_STREAMINFO_SIZE) {
+ // only the streaminfo packet
+ put_byte(pb, 0);
+ put_xiph_size(pb, codec->extradata_size);
+ av_log(s, AV_LOG_ERROR, "Only one packet\n");
+ }
+ put_buffer(pb, codec->extradata, codec->extradata_size);
+ return 0;
+}
+
+static void get_aac_sample_rates(AVFormatContext *s, AVCodecContext *codec, int *sample_rate, int *output_sample_rate)
+{
+ static const int aac_sample_rates[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000,
+ 24000, 22050, 16000, 12000, 11025, 8000,
+ };
+ int sri;
+
+ if (codec->extradata_size < 2) {
+ av_log(s, AV_LOG_WARNING, "No AAC extradata, unable to determine samplerate.\n");
+ return;
+ }
+
+ sri = ((codec->extradata[0] << 1) & 0xE) | (codec->extradata[1] >> 7);
+ if (sri > 12) {
+ av_log(s, AV_LOG_WARNING, "AAC samplerate index out of bounds\n");
+ return;
+ }
+ *sample_rate = aac_sample_rates[sri];
+
+ // if sbr, get output sample rate as well
+ if (codec->extradata_size == 5) {
+ sri = (codec->extradata[4] >> 3) & 0xF;
+ if (sri > 12) {
+ av_log(s, AV_LOG_WARNING, "AAC output samplerate index out of bounds\n");
+ return;
+ }
+ *output_sample_rate = aac_sample_rates[sri];
+ }
+}
+
+static int mkv_write_codecprivate(AVFormatContext *s, ByteIOContext *pb, AVCodecContext *codec, int native_id)
+{
+ ByteIOContext dyn_cp;
+ uint8_t *codecpriv;
+ int ret = 0, codecpriv_size;
+
+ url_open_dyn_buf(&dyn_cp);
+
+ if (native_id) {
+ if (codec->codec_id == CODEC_ID_VORBIS || codec->codec_id == CODEC_ID_THEORA)
+ ret = put_xiph_codecpriv(s, &dyn_cp, codec);
+ else if (codec->codec_id == CODEC_ID_FLAC)
+ ret = put_flac_codecpriv(s, &dyn_cp, codec);
+ else if (codec->extradata_size)
+ put_buffer(&dyn_cp, codec->extradata, codec->extradata_size);
+ } else if (codec->codec_type == CODEC_TYPE_VIDEO) {
+ if (!codec->codec_tag)
+ codec->codec_tag = codec_get_tag(codec_bmp_tags, codec->codec_id);
+ if (!codec->codec_tag) {
+ av_log(s, AV_LOG_ERROR, "No bmp codec ID found.");
+ ret = -1;
+ }
+
+ put_bmp_header(&dyn_cp, codec, codec_bmp_tags, 0);
+
+ } else if (codec->codec_type == CODEC_TYPE_AUDIO) {
+ if (!codec->codec_tag)
+ codec->codec_tag = codec_get_tag(codec_wav_tags, codec->codec_id);
+ if (!codec->codec_tag) {
+ av_log(s, AV_LOG_ERROR, "No wav codec ID found.");
+ ret = -1;
+ }
+
+ put_wav_header(&dyn_cp, codec);
+ }
+
+ codecpriv_size = url_close_dyn_buf(&dyn_cp, &codecpriv);
+ if (codecpriv_size)
+ put_ebml_binary(pb, MATROSKA_ID_CODECPRIVATE, codecpriv, codecpriv_size);
+ av_free(codecpriv);
+ return ret;
+}
+
+static int mkv_write_tracks(AVFormatContext *s)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ ebml_master tracks;
+ int i, j, ret;
+
+ ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_TRACKS, url_ftell(pb));
+ if (ret < 0) return ret;
+
+ tracks = start_ebml_master(pb, MATROSKA_ID_TRACKS, 0);
+ for (i = 0; i < s->nb_streams; i++) {
+ AVStream *st = s->streams[i];
+ AVCodecContext *codec = st->codec;
+ ebml_master subinfo, track;
+ int native_id = 0;
+ int bit_depth = av_get_bits_per_sample(codec->codec_id);
+ int sample_rate = codec->sample_rate;
+ int output_sample_rate = 0;
+
+ if (!bit_depth)
+ bit_depth = av_get_bits_per_sample_format(codec->sample_fmt);
+
+ if (codec->codec_id == CODEC_ID_AAC)
+ get_aac_sample_rates(s, codec, &sample_rate, &output_sample_rate);
+
+ track = start_ebml_master(pb, MATROSKA_ID_TRACKENTRY, 0);
+ put_ebml_uint (pb, MATROSKA_ID_TRACKNUMBER , i + 1);
+ put_ebml_uint (pb, MATROSKA_ID_TRACKUID , i + 1);
+ put_ebml_uint (pb, MATROSKA_ID_TRACKFLAGLACING , 0); // no lacing (yet)
+
+ if (st->language[0])
+ put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, st->language);
+ else
+ put_ebml_string(pb, MATROSKA_ID_TRACKLANGUAGE, "und");
+
+ // look for a codec ID string specific to mkv to use,
+ // if none are found, use AVI codes
+ for (j = 0; ff_mkv_codec_tags[j].id != CODEC_ID_NONE; j++) {
+ if (ff_mkv_codec_tags[j].id == codec->codec_id) {
+ put_ebml_string(pb, MATROSKA_ID_CODECID, ff_mkv_codec_tags[j].str);
+ native_id = 1;
+ break;
+ }
+ }
+
+ switch (codec->codec_type) {
+ case CODEC_TYPE_VIDEO:
+ put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_VIDEO);
+
+ if (!native_id)
+ // if there is no mkv-specific codec ID, use VFW mode
+ put_ebml_string(pb, MATROSKA_ID_CODECID, MATROSKA_CODEC_ID_VIDEO_VFW_FOURCC);
+
+ subinfo = start_ebml_master(pb, MATROSKA_ID_TRACKVIDEO, 0);
+ // XXX: interlace flag?
+ put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELWIDTH , codec->width);
+ put_ebml_uint (pb, MATROSKA_ID_VIDEOPIXELHEIGHT, codec->height);
+ if (codec->sample_aspect_ratio.num) {
+ AVRational dar = av_mul_q(codec->sample_aspect_ratio,
+ (AVRational){codec->width, codec->height});
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYWIDTH , dar.num);
+ put_ebml_uint(pb, MATROSKA_ID_VIDEODISPLAYHEIGHT, dar.den);
+ }
+ end_ebml_master(pb, subinfo);
+ break;
+
+ case CODEC_TYPE_AUDIO:
+ put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_AUDIO);
+
+ if (!native_id)
+ // no mkv-specific ID, use ACM mode
+ put_ebml_string(pb, MATROSKA_ID_CODECID, MATROSKA_CODEC_ID_AUDIO_ACM);
+
+ subinfo = start_ebml_master(pb, MATROSKA_ID_TRACKAUDIO, 0);
+ put_ebml_uint (pb, MATROSKA_ID_AUDIOCHANNELS , codec->channels);
+ put_ebml_float (pb, MATROSKA_ID_AUDIOSAMPLINGFREQ, sample_rate);
+ if (output_sample_rate)
+ put_ebml_float(pb, MATROSKA_ID_AUDIOOUTSAMPLINGFREQ, output_sample_rate);
+ if (bit_depth)
+ put_ebml_uint(pb, MATROSKA_ID_AUDIOBITDEPTH, bit_depth);
+ end_ebml_master(pb, subinfo);
+ break;
+
+ case CODEC_TYPE_SUBTITLE:
+ put_ebml_uint(pb, MATROSKA_ID_TRACKTYPE, MATROSKA_TRACK_TYPE_SUBTITLE);
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "Only audio, video, and subtitles are supported for Matroska.");
+ break;
+ }
+ ret = mkv_write_codecprivate(s, pb, codec, native_id);
+ if (ret < 0) return ret;
+
+ end_ebml_master(pb, track);
+
+ // ms precision is the de-facto standard timescale for mkv files
+ av_set_pts_info(st, 64, 1, 1000);
+ }
+ end_ebml_master(pb, tracks);
+ return 0;
+}
+
+static int mkv_write_header(AVFormatContext *s)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ ebml_master ebml_header, segment_info;
+ int ret;
+
+ mkv->md5_ctx = av_mallocz(av_md5_size);
+ av_md5_init(mkv->md5_ctx);
+
+ ebml_header = start_ebml_master(pb, EBML_ID_HEADER, 0);
+ put_ebml_uint (pb, EBML_ID_EBMLVERSION , 1);
+ put_ebml_uint (pb, EBML_ID_EBMLREADVERSION , 1);
+ put_ebml_uint (pb, EBML_ID_EBMLMAXIDLENGTH , 4);
+ put_ebml_uint (pb, EBML_ID_EBMLMAXSIZELENGTH , 8);
+ put_ebml_string (pb, EBML_ID_DOCTYPE , "matroska");
+ put_ebml_uint (pb, EBML_ID_DOCTYPEVERSION , 2);
+ put_ebml_uint (pb, EBML_ID_DOCTYPEREADVERSION , 2);
+ end_ebml_master(pb, ebml_header);
+
+ mkv->segment = start_ebml_master(pb, MATROSKA_ID_SEGMENT, 0);
+ mkv->segment_offset = url_ftell(pb);
+
+ // we write 2 seek heads - one at the end of the file to point to each
+ // cluster, and one at the beginning to point to all other level one
+ // elements (including the seek head at the end of the file), which
+ // isn't more than 10 elements if we only write one of each other
+ // currently defined level 1 element
+ mkv->main_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 10);
+ mkv->cluster_seekhead = mkv_start_seekhead(pb, mkv->segment_offset, 0);
+ if (mkv->main_seekhead == NULL || mkv->cluster_seekhead == NULL)
+ return AVERROR(ENOMEM);
+
+ ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_INFO, url_ftell(pb));
+ if (ret < 0) return ret;
+
+ segment_info = start_ebml_master(pb, MATROSKA_ID_INFO, 0);
+ put_ebml_uint(pb, MATROSKA_ID_TIMECODESCALE, 1000000);
+ if (strlen(s->title))
+ put_ebml_string(pb, MATROSKA_ID_TITLE, s->title);
+ if (!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) {
+ put_ebml_string(pb, MATROSKA_ID_MUXINGAPP , LIBAVFORMAT_IDENT);
+ put_ebml_string(pb, MATROSKA_ID_WRITINGAPP, LIBAVFORMAT_IDENT);
+
+ // reserve space to write the segment UID later
+ mkv->segment_uid = url_ftell(pb);
+ put_ebml_void(pb, 19);
+ }
+
+ // reserve space for the duration
+ mkv->duration = 0;
+ mkv->duration_offset = url_ftell(pb);
+ put_ebml_void(pb, 11); // assumes double-precision float to be written
+ end_ebml_master(pb, segment_info);
+
+ ret = mkv_write_tracks(s);
+ if (ret < 0) return ret;
+
+ ret = mkv_add_seekhead_entry(mkv->cluster_seekhead, MATROSKA_ID_CLUSTER, url_ftell(pb));
+ if (ret < 0) return ret;
+
+ mkv->cluster_pos = url_ftell(pb);
+ mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER, 0);
+ put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, 0);
+ mkv->cluster_pts = 0;
+
+ mkv->cues = mkv_start_cues(mkv->segment_offset);
+ if (mkv->cues == NULL)
+ return AVERROR(ENOMEM);
+
+ return 0;
+}
+
+static int mkv_block_size(AVPacket *pkt)
+{
+ int size = 4; // track num + timecode + flags
+ return size + pkt->size;
+}
+
+static int mkv_blockgroup_size(AVPacket *pkt)
+{
+ int size = mkv_block_size(pkt);
+ size += ebml_num_size(size);
+ size += 2; // EBML ID for block and block duration
+ size += 8; // max size of block duration
+ size += ebml_num_size(size);
+ size += 1; // blockgroup EBML ID
+ return size;
+}
+
+static void mkv_write_block(AVFormatContext *s, unsigned int blockid, AVPacket *pkt, int flags)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+
+ av_log(s, AV_LOG_DEBUG, "Writing block at offset %" PRIu64 ", size %d, "
+ "pts %" PRId64 ", dts %" PRId64 ", duration %d, flags %d\n",
+ url_ftell(pb), pkt->size, pkt->pts, pkt->dts, pkt->duration, flags);
+ put_ebml_id(pb, blockid);
+ put_ebml_num(pb, mkv_block_size(pkt), 0);
+ put_byte(pb, 0x80 | (pkt->stream_index + 1)); // this assumes stream_index is less than 126
+ put_be16(pb, pkt->pts - mkv->cluster_pts);
+ put_byte(pb, flags);
+ put_buffer(pb, pkt->data, pkt->size);
+}
+
+static int mkv_write_packet(AVFormatContext *s, AVPacket *pkt)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ AVCodecContext *codec = s->streams[pkt->stream_index]->codec;
+ int keyframe = !!(pkt->flags & PKT_FLAG_KEY);
+ int ret;
+
+ // start a new cluster every 5 MB or 5 sec
+ if (url_ftell(pb) > mkv->cluster_pos + 5*1024*1024 || pkt->pts > mkv->cluster_pts + 5000) {
+ av_log(s, AV_LOG_DEBUG, "Starting new cluster at offset %" PRIu64
+ " bytes, pts %" PRIu64 "\n", url_ftell(pb), pkt->pts);
+ end_ebml_master(pb, mkv->cluster);
+
+ ret = mkv_add_seekhead_entry(mkv->cluster_seekhead, MATROSKA_ID_CLUSTER, url_ftell(pb));
+ if (ret < 0) return ret;
+
+ mkv->cluster_pos = url_ftell(pb);
+ mkv->cluster = start_ebml_master(pb, MATROSKA_ID_CLUSTER, 0);
+ put_ebml_uint(pb, MATROSKA_ID_CLUSTERTIMECODE, pkt->pts);
+ mkv->cluster_pts = pkt->pts;
+ av_md5_update(mkv->md5_ctx, pkt->data, FFMIN(200, pkt->size));
+ }
+
+ if (codec->codec_type != CODEC_TYPE_SUBTITLE) {
+ mkv_write_block(s, MATROSKA_ID_SIMPLEBLOCK, pkt, keyframe << 7);
+ } else {
+ ebml_master blockgroup = start_ebml_master(pb, MATROSKA_ID_BLOCKGROUP, mkv_blockgroup_size(pkt));
+ mkv_write_block(s, MATROSKA_ID_BLOCK, pkt, 0);
+ put_ebml_uint(pb, MATROSKA_ID_DURATION, pkt->duration);
+ end_ebml_master(pb, blockgroup);
+ }
+
+ if (codec->codec_type == CODEC_TYPE_VIDEO && keyframe) {
+ ret = mkv_add_cuepoint(mkv->cues, pkt, mkv->cluster_pos);
+ if (ret < 0) return ret;
+ }
+
+ mkv->duration = FFMAX(mkv->duration, pkt->pts + pkt->duration);
+ return 0;
+}
+
+static int mkv_write_trailer(AVFormatContext *s)
+{
+ MatroskaMuxContext *mkv = s->priv_data;
+ ByteIOContext *pb = &s->pb;
+ offset_t currentpos, second_seekhead, cuespos;
+ int ret;
+
+ end_ebml_master(pb, mkv->cluster);
+
+ if (!url_is_streamed(pb)) {
+ cuespos = mkv_write_cues(pb, mkv->cues, s->nb_streams);
+ second_seekhead = mkv_write_seekhead(pb, mkv->cluster_seekhead);
+
+ ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_CUES , cuespos);
+ if (ret < 0) return ret;
+ ret = mkv_add_seekhead_entry(mkv->main_seekhead, MATROSKA_ID_SEEKHEAD, second_seekhead);
+ if (ret < 0) return ret;
+ mkv_write_seekhead(pb, mkv->main_seekhead);
+
+ // update the duration
+ av_log(s, AV_LOG_DEBUG, "end duration = %" PRIu64 "\n", mkv->duration);
+ currentpos = url_ftell(pb);
+ url_fseek(pb, mkv->duration_offset, SEEK_SET);
+ put_ebml_float(pb, MATROSKA_ID_DURATION, mkv->duration);
+
+ // write the md5sum of some frames as the segment UID
+ if (!(s->streams[0]->codec->flags & CODEC_FLAG_BITEXACT)) {
+ uint8_t segment_uid[16];
+ av_md5_final(mkv->md5_ctx, segment_uid);
+ url_fseek(pb, mkv->segment_uid, SEEK_SET);
+ put_ebml_binary(pb, MATROSKA_ID_SEGMENTUID, segment_uid, 16);
+ }
+ url_fseek(pb, currentpos, SEEK_SET);
+ }
+
+ end_ebml_master(pb, mkv->segment);
+ av_free(mkv->md5_ctx);
+ return 0;
+}
+
+AVOutputFormat matroska_muxer = {
+ "matroska",
+ "Matroska File Format",
+ "video/x-matroska",
+ "mkv",
+ sizeof(MatroskaMuxContext),
+ CODEC_ID_MP2,
+ CODEC_ID_MPEG4,
+ mkv_write_header,
+ mkv_write_packet,
+ mkv_write_trailer,
+ .codec_tag = (const AVCodecTag*[]){codec_bmp_tags, codec_wav_tags, 0},
+ // MEANX .subtitle_codec = CODEC_ID_TEXT,
+};
+
+AVOutputFormat matroska_audio_muxer = {
+ "matroska",
+ "Matroska File Format",
+ "audio/x-matroska",
+ "mka",
+ sizeof(MatroskaMuxContext),
+ CODEC_ID_MP2,
+ CODEC_ID_NONE,
+ mkv_write_header,
+ mkv_write_packet,
+ mkv_write_trailer,
+ .codec_tag = (const AVCodecTag*[]){codec_wav_tags, 0},
+};
+// MEANX
+//
+int matroskaenc_init(void)
+{
+ av_register_output_format(&matroska_muxer);
+ return 0;
+}
+
Modified: branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavutil/crc.h
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavutil/crc.h 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_libraries/ADM_lavutil/crc.h 2007-09-08 10:54:35 UTC (rev 3582)
@@ -26,6 +26,13 @@
typedef uint32_t AVCRC;
+#define AV_CRC_8_ATM 0x07
+#define AV_CRC_16 0x8005
+#define AV_CRC_16_CCITT 0x1021
+#define AV_CRC_32_IEEE 0x04C11DB7L
+//! reversed bitorder version of AV_CRC_32_IEEE
+#define AV_CRC_32_IEEE_LE 0xEDB88320L
+
#if LIBAVUTIL_VERSION_INT < (50<<16)
extern AVCRC *av_crcEDB88320;
extern AVCRC *av_crc04C11DB7;
Modified: branches/avidemux_2.4_branch/avidemux/ADM_outputs/oplug_mp4/oplug_mp4.cpp
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_outputs/oplug_mp4/oplug_mp4.cpp 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_outputs/oplug_mp4/oplug_mp4.cpp 2007-09-08 10:54:35 UTC (rev 3582)
@@ -125,10 +125,14 @@
uint32_t totalAudioSize=0;
uint32_t sent=0;
- if(type==ADM_PSP)
- muxerType=MUXER_PSP;
- else
- muxerType=MUXER_MP4;
+ switch(type)
+ {
+ case ADM_PSP:muxerType=MUXER_PSP;break;
+ case ADM_MP4:muxerType=MUXER_MP4;break;
+ case ADM_MATROSKA:muxerType=MUXER_MATROSKA;break;
+ default:
+ ADM_assert(0);
+ }
// Setup video
if(videoProcessMode())
Modified: branches/avidemux_2.4_branch/avidemux/ADM_script/ADM_container.h
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_script/ADM_container.h 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_script/ADM_container.h 2007-09-08 10:54:35 UTC (rev 3582)
@@ -28,7 +28,8 @@
MK_CONT(MP4),
MK_CONT(PSP),
MK_CONT(FLV),
- MK_CONT(DUMMY)
+ MK_CONT(DUMMY),
+ MK_CONT(MATROSKA)
};
#define NB_CONT (sizeof(container)/sizeof(ADM_CONTAINER))
#endif
Modified: branches/avidemux_2.4_branch/avidemux/ADM_video/ADM_genvideo.hxx
===================================================================
--- branches/avidemux_2.4_branch/avidemux/ADM_video/ADM_genvideo.hxx 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/ADM_video/ADM_genvideo.hxx 2007-09-08 10:54:35 UTC (rev 3582)
@@ -150,7 +150,7 @@
#define CREATOR(x,clss) return new clss(in,x);
#define BUILD_CREATE(name,clss) AVDMGenericVideoStream *name(AVDMGenericVideoStream *in, CONFcouple *conf) \
{ CREATOR(conf,clss); }
-
+#define VARIABLE_PARAMS 0xff
#define SCRIPT_CREATE(name,clss,tmplate) \
AVDMGenericVideoStream *name (AVDMGenericVideoStream *in, int n,Arg *args); \
AVDMGenericVideoStream *name (AVDMGenericVideoStream *in, int n,Arg *args) \
Modified: branches/avidemux_2.4_branch/avidemux/gui_savenew.cpp
===================================================================
--- branches/avidemux_2.4_branch/avidemux/gui_savenew.cpp 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/avidemux/gui_savenew.cpp 2007-09-08 10:54:35 UTC (rev 3582)
@@ -180,6 +180,7 @@
break;
case ADM_MP4:
case ADM_PSP:
+ case ADM_MATROSKA:
ret=oplug_mp4(name,UI_GetCurrentFormat());
break;
Modified: branches/avidemux_2.4_branch/config.h.cmake
===================================================================
--- branches/avidemux_2.4_branch/config.h.cmake 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/config.h.cmake 2007-09-08 10:54:35 UTC (rev 3582)
@@ -77,6 +77,7 @@
#cmakedefine CONFIG_MJPEG_DECODER
#cmakedefine CONFIG_MJPEG_ENCODER
#cmakedefine CONFIG_MOV_MUXER
+#cmakedefine CONFIG_MATROSKA_MUXER
#cmakedefine CONFIG_MP2_ENCODER
#cmakedefine CONFIG_MP4_MUXER
#cmakedefine CONFIG_MPEG1VIDEO_DECODER
Modified: branches/avidemux_2.4_branch/configure.in.in
===================================================================
--- branches/avidemux_2.4_branch/configure.in.in 2007-09-08 10:53:53 UTC (rev 3581)
+++ branches/avidemux_2.4_branch/configure.in.in 2007-09-08 10:54:35 UTC (rev 3582)
@@ -1414,6 +1414,7 @@
AC_DEFINE(CONFIG_PSP_MUXER,1,[CONFIG_MUXERS])
AC_DEFINE(CONFIG_MP4_MUXER,1,[CONFIG_MUXERS])
AC_DEFINE(CONFIG_MOV_MUXER,1,[CONFIG_MUXERS])
+AC_DEFINE(CONFIG_MATROSKA_MUXER,1,[CONFIG_MATROSKA_MUXERS])
AC_DEFINE(HAVE_THREADS,1,[HAVE_THREADS])
AC_DEFINE(ENABLE_THREADS,1,[ENABLE_THREADS])
More information about the Avidemux-svn-commit
mailing list