mirror of
https://github.com/mpv-player/mpv
synced 2024-12-23 15:22:09 +00:00
the long-waited MUXER layer, and new MPEG-PS muxer
patch by Andriy N. Gritsenko <andrej@lucky.net> git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@8586 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
bc9afe8d39
commit
bf46a109ed
@ -6,7 +6,7 @@
|
||||
#include "wine/avifmt.h"
|
||||
#include "wine/vfw.h"
|
||||
|
||||
#include "aviwrite.h"
|
||||
#include "muxer.h"
|
||||
|
||||
static const short h263_format[8][2] = {
|
||||
{ 0, 0 },
|
||||
@ -149,8 +149,8 @@ int pos=0;
|
||||
int frames=0;
|
||||
FILE *f=fopen("paulvandykforanangel.viv","rb");
|
||||
FILE *f2=fopen("GB1.avi","wb");
|
||||
aviwrite_t* avi=aviwrite_new_muxer();
|
||||
aviwrite_stream_t* mux=aviwrite_new_stream(avi,AVIWRITE_TYPE_VIDEO);
|
||||
muxer_t* avi=muxer_new_muxer(MUXER_TYPE_AVI);
|
||||
muxer_stream_t* mux=muxer_new_stream(avi,MUXER_TYPE_VIDEO);
|
||||
//unsigned char* buffer=malloc(0x200000);
|
||||
int i,len;
|
||||
int v_id=0;
|
||||
@ -169,7 +169,7 @@ mux->bih->biSize=sizeof(BITMAPINFOHEADER);
|
||||
mux->bih->biPlanes=1;
|
||||
mux->bih->biBitCount=24;
|
||||
mux->bih->biCompression=0x6f766976;// 7669766f;
|
||||
aviwrite_write_header(avi,f2);
|
||||
muxer_write_header(avi,f2);
|
||||
|
||||
/*
|
||||
c=fgetc(f); if(c) printf("error! not vivo file?\n");
|
||||
@ -222,7 +222,7 @@ while((c=fgetc(f))>=0){
|
||||
// end of frame:
|
||||
printf("Frame size: %d\n",mux->buffer_len);
|
||||
h263_decode_picture_header(mux->buffer);
|
||||
aviwrite_write_chunk(avi,mux,f2,mux->buffer_len,0x10);
|
||||
muxer_write_chunk(avi,mux,f2,mux->buffer_len,0x10);
|
||||
mux->buffer_len=0;
|
||||
|
||||
if((v_id&0xF0)==0x10) fprintf(stderr,"hmm. last video packet %02X\n",v_id);
|
||||
@ -258,8 +258,8 @@ mux->bih->biWidth=width;
|
||||
mux->bih->biHeight=height;
|
||||
mux->bih->biSizeImage=3*width*height;
|
||||
|
||||
aviwrite_write_index(avi,f2);
|
||||
muxer_write_index(avi,f2);
|
||||
fseek(f2,0,SEEK_SET);
|
||||
aviwrite_write_header(avi,f2);
|
||||
muxer_write_header(avi,f2);
|
||||
|
||||
}
|
||||
|
@ -129,6 +129,16 @@ struct config info_conf[]={
|
||||
{NULL, NULL, 0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
struct config of_conf[]={
|
||||
{"avi", &out_file_format, CONF_TYPE_FLAG, 0, 0, MUXER_TYPE_AVI, NULL},
|
||||
{"mpeg", &out_file_format, CONF_TYPE_FLAG, 0, 0, MUXER_TYPE_MPEG, NULL},
|
||||
{"help", "\nAvailable output formats:\n"
|
||||
" avi - Microsoft Audio/Video Interleaved\n"
|
||||
" mpeg - MPEG-1 system stream format\n"
|
||||
"\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL},
|
||||
{NULL, NULL, 0, 0, 0, 0, NULL}
|
||||
};
|
||||
|
||||
static config_t mencoder_opts[]={
|
||||
/* name, pointer, type, flags, min, max */
|
||||
{"include", cfg_include, CONF_TYPE_FUNC_PARAM, CONF_NOSAVE, 0, 0, NULL}, /* this must be the first!!! */
|
||||
@ -156,6 +166,9 @@ static config_t mencoder_opts[]={
|
||||
{"oac", oac_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
|
||||
{"ovc", ovc_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
|
||||
|
||||
// output file format
|
||||
{"of", of_conf, CONF_TYPE_SUBCONFIG, 0, 0, 0, NULL},
|
||||
|
||||
// override FOURCC in output file
|
||||
{"ffourcc", &force_fourcc, CONF_TYPE_STRING, 0, 4, 4, NULL},
|
||||
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
#include "aviwrite.h"
|
||||
#include "muxer.h"
|
||||
|
||||
#include "img_format.h"
|
||||
#include "mp_image.h"
|
||||
@ -44,7 +44,7 @@
|
||||
|
||||
static int pass;
|
||||
extern char* passtmpfile;
|
||||
extern void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags);
|
||||
extern void mencoder_write_chunk(muxer_stream_t *s,int len,unsigned int flags);
|
||||
|
||||
#include <encore2.h>
|
||||
|
||||
@ -96,7 +96,7 @@ struct config divx4opts_conf[]={
|
||||
};
|
||||
|
||||
struct vf_priv_s {
|
||||
aviwrite_stream_t* mux;
|
||||
muxer_stream_t* mux;
|
||||
ENC_RESULT enc_result;
|
||||
ENC_FRAME enc_frame;
|
||||
void* enc_handle;
|
||||
@ -289,7 +289,7 @@ static int vf_open(vf_instance_t *vf, char* args){
|
||||
#endif
|
||||
vf->priv=malloc(sizeof(struct vf_priv_s));
|
||||
memset(vf->priv,0,sizeof(struct vf_priv_s));
|
||||
vf->priv->mux=(aviwrite_stream_t*)args;
|
||||
vf->priv->mux=(muxer_stream_t*)args;
|
||||
|
||||
mux_v->bih=malloc(sizeof(BITMAPINFOHEADER));
|
||||
mux_v->bih->biSize=sizeof(BITMAPINFOHEADER);
|
||||
|
@ -20,14 +20,14 @@
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
#include "aviwrite.h"
|
||||
#include "muxer.h"
|
||||
|
||||
#include "img_format.h"
|
||||
#include "mp_image.h"
|
||||
#include "vf.h"
|
||||
|
||||
extern char* passtmpfile;
|
||||
extern void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags);
|
||||
extern void mencoder_write_chunk(muxer_stream_t *s,int len,unsigned int flags);
|
||||
|
||||
//===========================================================================//
|
||||
|
||||
@ -175,7 +175,7 @@ struct config lavcopts_conf[]={
|
||||
#endif
|
||||
|
||||
struct vf_priv_s {
|
||||
aviwrite_stream_t* mux;
|
||||
muxer_stream_t* mux;
|
||||
AVCodecContext *context;
|
||||
AVFrame *pic;
|
||||
AVCodec *codec;
|
||||
@ -531,7 +531,7 @@ static int vf_open(vf_instance_t *vf, char* args){
|
||||
vf->put_image=put_image;
|
||||
vf->priv=malloc(sizeof(struct vf_priv_s));
|
||||
memset(vf->priv,0,sizeof(struct vf_priv_s));
|
||||
vf->priv->mux=(aviwrite_stream_t*)args;
|
||||
vf->priv->mux=(muxer_stream_t*)args;
|
||||
|
||||
/* XXX: hack: some of the MJPEG decoder DLL's needs exported huffman
|
||||
table, so we define a zero-table, also lavc mjpeg encoder is putting
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
#include "aviwrite.h"
|
||||
#include "muxer.h"
|
||||
|
||||
#include "img_format.h"
|
||||
#include "mp_image.h"
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
#include <libdv/dv.h>
|
||||
|
||||
extern void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags);
|
||||
extern void mencoder_write_chunk(muxer_stream_t *s,int len,unsigned int flags);
|
||||
|
||||
#ifndef DV_WIDTH
|
||||
#define DV_WIDTH 720
|
||||
@ -32,7 +32,7 @@ extern void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags
|
||||
#endif
|
||||
|
||||
struct vf_priv_s {
|
||||
aviwrite_stream_t* mux;
|
||||
muxer_stream_t* mux;
|
||||
dv_encoder_t* enc;
|
||||
|
||||
};
|
||||
@ -91,7 +91,7 @@ static int vf_open(vf_instance_t *vf, char* args){
|
||||
vf->put_image=put_image;
|
||||
vf->priv=malloc(sizeof(struct vf_priv_s));
|
||||
memset(vf->priv,0,sizeof(struct vf_priv_s));
|
||||
vf->priv->mux=(aviwrite_stream_t*)args;
|
||||
vf->priv->mux=(muxer_stream_t*)args;
|
||||
|
||||
vf->priv->enc=dv_encoder_new(1,1,1); // FIXME, parse some options!
|
||||
if(!vf->priv->enc) return 0;
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
#include "aviwrite.h"
|
||||
#include "muxer.h"
|
||||
|
||||
#include "img_format.h"
|
||||
#include "mp_image.h"
|
||||
@ -86,7 +86,7 @@ static long (*CountComponents)(ComponentDescription* desc);
|
||||
static OSErr (*GetComponentInfo)(Component prev,ComponentDescription* desc,Handle h1,Handle h2,Handle h3);
|
||||
|
||||
|
||||
extern void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags);
|
||||
extern void mencoder_write_chunk(muxer_stream_t *s,int len,unsigned int flags);
|
||||
|
||||
|
||||
//static int format=mmioFOURCC('S','V','Q','1');
|
||||
@ -111,7 +111,7 @@ static ImageSequence seq;
|
||||
|
||||
|
||||
struct vf_priv_s {
|
||||
aviwrite_stream_t* mux;
|
||||
muxer_stream_t* mux;
|
||||
//dv_encoder_t* enc;
|
||||
|
||||
};
|
||||
@ -279,7 +279,7 @@ static int vf_open(vf_instance_t *vf, char* args){
|
||||
vf->put_image=put_image;
|
||||
vf->priv=malloc(sizeof(struct vf_priv_s));
|
||||
memset(vf->priv,0,sizeof(struct vf_priv_s));
|
||||
vf->priv->mux=(aviwrite_stream_t*)args;
|
||||
vf->priv->mux=(muxer_stream_t*)args;
|
||||
|
||||
mux_v->bih=malloc(sizeof(BITMAPINFOHEADER)+MAX_IDSIZE);
|
||||
mux_v->bih->biSize=sizeof(BITMAPINFOHEADER)+MAX_IDSIZE;
|
||||
|
@ -10,18 +10,18 @@
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
#include "aviwrite.h"
|
||||
#include "muxer.h"
|
||||
|
||||
#include "img_format.h"
|
||||
#include "mp_image.h"
|
||||
#include "vf.h"
|
||||
|
||||
extern void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags);
|
||||
extern void mencoder_write_chunk(muxer_stream_t *s,int len,unsigned int flags);
|
||||
|
||||
//===========================================================================//
|
||||
|
||||
struct vf_priv_s {
|
||||
aviwrite_stream_t* mux;
|
||||
muxer_stream_t* mux;
|
||||
};
|
||||
#define mux_v (vf->priv->mux)
|
||||
|
||||
@ -61,7 +61,7 @@ static int vf_open(vf_instance_t *vf, char* args){
|
||||
vf->put_image=put_image;
|
||||
vf->priv=malloc(sizeof(struct vf_priv_s));
|
||||
memset(vf->priv,0,sizeof(struct vf_priv_s));
|
||||
vf->priv->mux=(aviwrite_stream_t*)args;
|
||||
vf->priv->mux=(muxer_stream_t*)args;
|
||||
|
||||
mux_v->bih=malloc(sizeof(BITMAPINFOHEADER));
|
||||
mux_v->bih->biSize=sizeof(BITMAPINFOHEADER);
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "../config.h"
|
||||
#ifdef USE_WIN32DLL
|
||||
@ -18,13 +19,13 @@
|
||||
#include "wine/vfw.h"
|
||||
#include "wine/avifmt.h"
|
||||
|
||||
#include "aviwrite.h"
|
||||
|
||||
#include "img_format.h"
|
||||
#include "mp_image.h"
|
||||
#include "vf.h"
|
||||
|
||||
extern void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags);
|
||||
#include "muxer.h"
|
||||
|
||||
extern void mencoder_write_chunk(muxer_stream_t *s,int len,unsigned int flags);
|
||||
|
||||
//===========================================================================//
|
||||
|
||||
@ -38,7 +39,7 @@ struct config vfwopts_conf[]={
|
||||
};
|
||||
|
||||
struct vf_priv_s {
|
||||
aviwrite_stream_t* mux;
|
||||
muxer_stream_t* mux;
|
||||
BITMAPINFOHEADER* bih;
|
||||
};
|
||||
|
||||
@ -256,7 +257,7 @@ static int vf_open(vf_instance_t *vf, char* args){
|
||||
vf->put_image=put_image;
|
||||
vf->priv=malloc(sizeof(struct vf_priv_s));
|
||||
memset(vf->priv,0,sizeof(struct vf_priv_s));
|
||||
vf->priv->mux=(aviwrite_stream_t*)args;
|
||||
vf->priv->mux=(muxer_stream_t*)args;
|
||||
|
||||
vfw_bih=malloc(sizeof(BITMAPINFOHEADER));
|
||||
vfw_bih->biSize=sizeof(BITMAPINFOHEADER);
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "demuxer.h"
|
||||
#include "stheader.h"
|
||||
|
||||
#include "aviwrite.h"
|
||||
#include "muxer.h"
|
||||
|
||||
#include "img_format.h"
|
||||
#include "mp_image.h"
|
||||
@ -65,7 +65,7 @@ static int const motion_presets[7] = {
|
||||
};
|
||||
|
||||
extern char* passtmpfile;
|
||||
extern void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags);
|
||||
extern void mencoder_write_chunk(muxer_stream_t *s,int len,unsigned int flags);
|
||||
|
||||
static int xvidenc_pass = 0;
|
||||
static int xvidenc_quality = 4;
|
||||
@ -132,7 +132,7 @@ struct config xvidencopts_conf[] = {
|
||||
};
|
||||
|
||||
struct vf_priv_s {
|
||||
aviwrite_stream_t* mux;
|
||||
muxer_stream_t* mux;
|
||||
XVID_ENC_FRAME enc_frame;
|
||||
void* enc_handle;
|
||||
vbr_control_t vbr_state;
|
||||
@ -487,7 +487,7 @@ vf_open(vf_instance_t *vf, char* args)
|
||||
vf->put_image = put_image;
|
||||
vf->priv = malloc(sizeof(struct vf_priv_s));
|
||||
memset(vf->priv, 0, sizeof(struct vf_priv_s));
|
||||
vf->priv->mux = (aviwrite_stream_t*)args;
|
||||
vf->priv->mux = (muxer_stream_t*)args;
|
||||
|
||||
vf->priv->mux->bih = malloc(sizeof(BITMAPINFOHEADER));
|
||||
vf->priv->mux->bih->biSize = sizeof(BITMAPINFOHEADER);
|
||||
|
@ -3,7 +3,7 @@ LIBNAME = libmpdemux.a
|
||||
|
||||
include ../config.mak
|
||||
|
||||
SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c aviwrite.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c
|
||||
SRCS = mp3_hdr.c video.c mpeg_hdr.c cache2.c asfheader.c aviheader.c aviprint.c muxer.c muxer_avi.c muxer_mpeg.c demux_asf.c demux_avi.c demux_mov.c parse_mp4.c demux_mpg.c demux_pva.c demux_viv.c demuxer.c dvdauth.c dvdnav_stream.c open.c parse_es.c stream.c tv.c tvi_dummy.c tvi_v4l.c tvi_bsdbt848.c frequencies.c demux_fli.c demux_real.c demux_y4m.c yuv4mpeg.c yuv4mpeg_ratio.c demux_nuv.c demux_film.c demux_roq.c mf.c demux_mf.c demux_audio.c demux_demuxers.c demux_ogg.c demux_bmp.c cdda.c demux_rawaudio.c cddb.c cdinfo.c demux_rawdv.c ai_alsa.c ai_oss.c audio_in.c demux_smjpeg.c
|
||||
ifeq ($(XMMS_PLUGINS),yes)
|
||||
SRCS += demux_xmms.c
|
||||
endif
|
||||
|
@ -1,56 +0,0 @@
|
||||
|
||||
#define AVIWRITE_MAX_STREAMS 16
|
||||
|
||||
#define AVIWRITE_TYPE_VIDEO 0
|
||||
#define AVIWRITE_TYPE_AUDIO 1
|
||||
|
||||
typedef struct {
|
||||
// muxer data:
|
||||
int type; // audio or video
|
||||
int id; // stream no
|
||||
unsigned int ckid; // chunk id (00dc 01wb etc)
|
||||
double timer;
|
||||
off_t size;
|
||||
// buffering:
|
||||
unsigned char *buffer;
|
||||
unsigned int buffer_size;
|
||||
unsigned int buffer_len;
|
||||
// source stream:
|
||||
void* source; // sh_audio or sh_video
|
||||
int codec; // codec used for encoding. 0 means copy
|
||||
// avi stream header:
|
||||
AVIStreamHeader h; // Rate/Scale and SampleSize must be filled by caller!
|
||||
// stream specific:
|
||||
WAVEFORMATEX *wf;
|
||||
BITMAPINFOHEADER *bih; // in format
|
||||
} aviwrite_stream_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int id;
|
||||
char *text;
|
||||
} aviwrite_info_t;
|
||||
|
||||
typedef struct {
|
||||
// encoding:
|
||||
MainAVIHeader avih;
|
||||
unsigned int movi_start;
|
||||
unsigned int movi_end;
|
||||
unsigned int file_end;
|
||||
// index:
|
||||
AVIINDEXENTRY *idx;
|
||||
int idx_pos;
|
||||
int idx_size;
|
||||
// streams:
|
||||
//int num_streams;
|
||||
aviwrite_stream_t* def_v; // default video stream (for general headers)
|
||||
aviwrite_stream_t* streams[AVIWRITE_MAX_STREAMS];
|
||||
} aviwrite_t;
|
||||
|
||||
aviwrite_stream_t* aviwrite_new_stream(aviwrite_t *muxer,int type);
|
||||
aviwrite_t* aviwrite_new_muxer();
|
||||
void aviwrite_write_chunk(aviwrite_t *muxer,aviwrite_stream_t *s, FILE *f,int len,unsigned int flags);
|
||||
void aviwrite_write_header(aviwrite_t *muxer,FILE *f);
|
||||
void aviwrite_write_index(aviwrite_t *muxer,FILE *f);
|
||||
|
||||
|
||||
|
28
libmpdemux/muxer.c
Normal file
28
libmpdemux/muxer.c
Normal file
@ -0,0 +1,28 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "../version.h"
|
||||
|
||||
#include "wine/mmreg.h"
|
||||
#include "wine/avifmt.h"
|
||||
#include "wine/vfw.h"
|
||||
|
||||
#include "muxer.h"
|
||||
|
||||
muxer_t* muxer_new_muxer(int type){
|
||||
muxer_t* muxer=malloc(sizeof(muxer_t));
|
||||
memset(muxer,0,sizeof(muxer_t));
|
||||
switch (type) {
|
||||
case MUXER_TYPE_MPEG:
|
||||
muxer_init_muxer_mpeg(muxer);
|
||||
break;
|
||||
case MUXER_TYPE_AVI:
|
||||
default:
|
||||
muxer_init_muxer_avi(muxer);
|
||||
}
|
||||
return muxer;
|
||||
}
|
74
libmpdemux/muxer.h
Normal file
74
libmpdemux/muxer.h
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
#define MUXER_MAX_STREAMS 16
|
||||
|
||||
#define MUXER_TYPE_VIDEO 0
|
||||
#define MUXER_TYPE_AUDIO 1
|
||||
|
||||
#define MUXER_TYPE_AVI 0
|
||||
#define MUXER_TYPE_MPEG 1
|
||||
|
||||
#define MUXER_MPEG_BLOCKSIZE 2048 // 2048 or 2324 - ?
|
||||
|
||||
typedef struct {
|
||||
// muxer data:
|
||||
int type; // audio or video
|
||||
int id; // stream no
|
||||
uint32_t ckid; // chunk id (00dc 01wb etc)
|
||||
double timer;
|
||||
off_t size;
|
||||
// buffering:
|
||||
unsigned char *buffer;
|
||||
unsigned int buffer_size;
|
||||
unsigned int buffer_len;
|
||||
// mpeg block buffer:
|
||||
unsigned char *b_buffer;
|
||||
unsigned int b_buffer_ptr;
|
||||
// source stream:
|
||||
void* source; // sh_audio or sh_video
|
||||
int codec; // codec used for encoding. 0 means copy
|
||||
// avi stream header:
|
||||
AVIStreamHeader h; // Rate/Scale and SampleSize must be filled by caller!
|
||||
// stream specific:
|
||||
WAVEFORMATEX *wf;
|
||||
BITMAPINFOHEADER *bih; // in format
|
||||
// mpeg specific:
|
||||
unsigned int gop_start; // frame number of this GOP start
|
||||
size_t ipb[3]; // sizes of I/P/B frames
|
||||
} muxer_stream_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t id;
|
||||
char *text;
|
||||
} muxer_info_t;
|
||||
|
||||
typedef struct muxer_t{
|
||||
// encoding:
|
||||
MainAVIHeader avih;
|
||||
unsigned int movi_start;
|
||||
unsigned int movi_end;
|
||||
unsigned int file_end; // for MPEG it's system timestamp in 1/90000 s
|
||||
// index:
|
||||
AVIINDEXENTRY *idx;
|
||||
int idx_pos;
|
||||
int idx_size;
|
||||
// streams:
|
||||
int num_videos; // for MPEG recalculations
|
||||
unsigned int sysrate; // max rate in bytes/s
|
||||
//int num_streams;
|
||||
muxer_stream_t* def_v; // default video stream (for general headers)
|
||||
muxer_stream_t* streams[MUXER_MAX_STREAMS];
|
||||
void (*cont_write_chunk)(struct muxer_t *,muxer_stream_t *,FILE *,size_t,unsigned int);
|
||||
void (*cont_write_header)(struct muxer_t *,FILE *);
|
||||
void (*cont_write_index)(struct muxer_t *,FILE *);
|
||||
muxer_stream_t* (*cont_new_stream)(struct muxer_t *,int);
|
||||
} muxer_t;
|
||||
|
||||
muxer_t* muxer_new_muxer(int type);
|
||||
#define muxer_new_stream(muxer,a) muxer->cont_new_stream(muxer,a)
|
||||
#define muxer_write_chunk(muxer,a,b,c,d) muxer->cont_write_chunk(muxer,a,b,c,d)
|
||||
#define muxer_write_header(muxer,f) muxer->cont_write_header(muxer,f)
|
||||
#define muxer_write_index(muxer,f) muxer->cont_write_index(muxer,f)
|
||||
|
||||
void muxer_init_muxer_avi(muxer_t *);
|
||||
void muxer_init_muxer_mpeg(muxer_t *);
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "../version.h"
|
||||
@ -16,7 +16,7 @@
|
||||
#include "wine/vfw.h"
|
||||
#include "bswap.h"
|
||||
|
||||
#include "aviwrite.h"
|
||||
#include "muxer.h"
|
||||
#include "aviheader.h"
|
||||
|
||||
extern char *info_name;
|
||||
@ -27,14 +27,14 @@ extern char *info_copyright;
|
||||
extern char *info_sourceform;
|
||||
extern char *info_comment;
|
||||
|
||||
aviwrite_stream_t* aviwrite_new_stream(aviwrite_t *muxer,int type){
|
||||
aviwrite_stream_t* s;
|
||||
if(muxer->avih.dwStreams>=AVIWRITE_MAX_STREAMS){
|
||||
printf("Too many streams! increase AVIWRITE_MAX_STREAMS !\n");
|
||||
static muxer_stream_t* avifile_new_stream(muxer_t *muxer,int type){
|
||||
muxer_stream_t* s;
|
||||
if(muxer->avih.dwStreams>=MUXER_MAX_STREAMS){
|
||||
printf("Too many streams! increase MUXER_MAX_STREAMS !\n");
|
||||
return NULL;
|
||||
}
|
||||
s=malloc(sizeof(aviwrite_stream_t));
|
||||
memset(s,0,sizeof(aviwrite_stream_t));
|
||||
s=malloc(sizeof(muxer_stream_t));
|
||||
memset(s,0,sizeof(muxer_stream_t));
|
||||
if(!s) return NULL; // no mem!?
|
||||
muxer->streams[muxer->avih.dwStreams]=s;
|
||||
s->type=type;
|
||||
@ -42,12 +42,12 @@ aviwrite_stream_t* aviwrite_new_stream(aviwrite_t *muxer,int type){
|
||||
s->timer=0.0;
|
||||
s->size=0;
|
||||
switch(type){
|
||||
case AVIWRITE_TYPE_VIDEO:
|
||||
case MUXER_TYPE_VIDEO:
|
||||
s->ckid=mmioFOURCC(('0'+s->id/10),('0'+(s->id%10)),'d','c');
|
||||
s->h.fccType=streamtypeVIDEO;
|
||||
if(!muxer->def_v) muxer->def_v=s;
|
||||
break;
|
||||
case AVIWRITE_TYPE_AUDIO:
|
||||
case MUXER_TYPE_AUDIO:
|
||||
s->ckid=mmioFOURCC(('0'+s->id/10),('0'+(s->id%10)),'w','b');
|
||||
s->h.fccType=streamtypeAUDIO;
|
||||
break;
|
||||
@ -59,12 +59,6 @@ aviwrite_stream_t* aviwrite_new_stream(aviwrite_t *muxer,int type){
|
||||
return s;
|
||||
}
|
||||
|
||||
aviwrite_t* aviwrite_new_muxer(){
|
||||
aviwrite_t* muxer=malloc(sizeof(aviwrite_t));
|
||||
memset(muxer,0,sizeof(aviwrite_t));
|
||||
return muxer;
|
||||
}
|
||||
|
||||
static void write_avi_chunk(FILE *f,unsigned int id,int len,void* data){
|
||||
int le_len = le2me_32(len);
|
||||
int le_id = le2me_32(id);
|
||||
@ -93,7 +87,7 @@ if(len>0){
|
||||
}
|
||||
}
|
||||
|
||||
void aviwrite_write_chunk(aviwrite_t *muxer,aviwrite_stream_t *s, FILE *f,int len,unsigned int flags){
|
||||
static void avifile_write_chunk(muxer_t *muxer,muxer_stream_t *s, FILE *f,size_t len,unsigned int flags){
|
||||
|
||||
// add to the index:
|
||||
if(muxer->idx_pos>=muxer->idx_size){
|
||||
@ -120,7 +114,7 @@ void aviwrite_write_chunk(aviwrite_t *muxer,aviwrite_stream_t *s, FILE *f,int le
|
||||
}
|
||||
s->timer=(double)s->h.dwLength*s->h.dwScale/s->h.dwRate;
|
||||
s->size+=len;
|
||||
if(len>s->h.dwSuggestedBufferSize) s->h.dwSuggestedBufferSize=len;
|
||||
if((unsigned int)len>s->h.dwSuggestedBufferSize) s->h.dwSuggestedBufferSize=len;
|
||||
|
||||
}
|
||||
|
||||
@ -140,11 +134,11 @@ static void write_avi_list(FILE *f,unsigned int id,int len){
|
||||
// muxer->streams[i]->wf->cbSize
|
||||
#define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(((wf)->cbSize)?((wf)->cbSize-2):0))
|
||||
|
||||
void aviwrite_write_header(aviwrite_t *muxer,FILE *f){
|
||||
unsigned int riff[3];
|
||||
int i;
|
||||
static void avifile_write_header(muxer_t *muxer,FILE *f){
|
||||
uint32_t riff[3];
|
||||
unsigned int i;
|
||||
unsigned int hdrsize;
|
||||
aviwrite_info_t info[16];
|
||||
muxer_info_t info[16];
|
||||
|
||||
// RIFF header:
|
||||
riff[0]=mmioFOURCC('R','I','F','F');
|
||||
@ -173,10 +167,10 @@ void aviwrite_write_header(aviwrite_t *muxer,FILE *f){
|
||||
hdrsize+=12; // LIST
|
||||
hdrsize+=sizeof(muxer->streams[i]->h)+8; // strh
|
||||
switch(muxer->streams[i]->type){
|
||||
case AVIWRITE_TYPE_VIDEO:
|
||||
case MUXER_TYPE_VIDEO:
|
||||
hdrsize+=muxer->streams[i]->bih->biSize+8; // strf
|
||||
break;
|
||||
case AVIWRITE_TYPE_AUDIO:
|
||||
case MUXER_TYPE_AUDIO:
|
||||
hdrsize+=WFSIZE(muxer->streams[i]->wf)+8; // strf
|
||||
break;
|
||||
}
|
||||
@ -191,10 +185,10 @@ void aviwrite_write_header(aviwrite_t *muxer,FILE *f){
|
||||
for(i=0;i<muxer->avih.dwStreams;i++){
|
||||
hdrsize=sizeof(muxer->streams[i]->h)+8; // strh
|
||||
switch(muxer->streams[i]->type){
|
||||
case AVIWRITE_TYPE_VIDEO:
|
||||
case MUXER_TYPE_VIDEO:
|
||||
hdrsize+=muxer->streams[i]->bih->biSize+8; // strf
|
||||
break;
|
||||
case AVIWRITE_TYPE_AUDIO:
|
||||
case MUXER_TYPE_AUDIO:
|
||||
hdrsize+=WFSIZE(muxer->streams[i]->wf)+8; // strf
|
||||
break;
|
||||
}
|
||||
@ -204,7 +198,7 @@ void aviwrite_write_header(aviwrite_t *muxer,FILE *f){
|
||||
le2me_AVIStreamHeader(&muxer->streams[i]->h);
|
||||
|
||||
switch(muxer->streams[i]->type){
|
||||
case AVIWRITE_TYPE_VIDEO:
|
||||
case MUXER_TYPE_VIDEO:
|
||||
{
|
||||
int biSize=muxer->streams[i]->bih->biSize;
|
||||
le2me_BITMAPINFOHEADER(muxer->streams[i]->bih);
|
||||
@ -212,7 +206,7 @@ void aviwrite_write_header(aviwrite_t *muxer,FILE *f){
|
||||
le2me_BITMAPINFOHEADER(muxer->streams[i]->bih);
|
||||
}
|
||||
break;
|
||||
case AVIWRITE_TYPE_AUDIO:
|
||||
case MUXER_TYPE_AUDIO:
|
||||
{
|
||||
int wfsize = WFSIZE(muxer->streams[i]->wf);
|
||||
le2me_WAVEFORMATEX(muxer->streams[i]->wf);
|
||||
@ -280,7 +274,7 @@ info[i].id=0;
|
||||
muxer->movi_start=ftell(f);
|
||||
}
|
||||
|
||||
void aviwrite_write_index(aviwrite_t *muxer,FILE *f){
|
||||
static void avifile_write_index(muxer_t *muxer,FILE *f){
|
||||
muxer->movi_end=ftell(f);
|
||||
if(muxer->idx && muxer->idx_pos>0){
|
||||
int i;
|
||||
@ -295,3 +289,9 @@ void aviwrite_write_index(aviwrite_t *muxer,FILE *f){
|
||||
muxer->file_end=ftell(f);
|
||||
}
|
||||
|
||||
void muxer_init_muxer_avi(muxer_t *muxer){
|
||||
muxer->cont_new_stream = &avifile_new_stream;
|
||||
muxer->cont_write_chunk = &avifile_write_chunk;
|
||||
muxer->cont_write_header = &avifile_write_header;
|
||||
muxer->cont_write_index = &avifile_write_index;
|
||||
}
|
434
libmpdemux/muxer_mpeg.c
Normal file
434
libmpdemux/muxer_mpeg.c
Normal file
@ -0,0 +1,434 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "../version.h"
|
||||
|
||||
#include "wine/mmreg.h"
|
||||
#include "wine/avifmt.h"
|
||||
#include "wine/vfw.h"
|
||||
#include "bswap.h"
|
||||
|
||||
#include "muxer.h"
|
||||
|
||||
// 18 bytes reserved for block headers and STD
|
||||
#define MUXER_MPEG_DATASIZE (MUXER_MPEG_BLOCKSIZE-18)
|
||||
|
||||
// ISO-11172 requirements
|
||||
#define MPEG_MAX_PTS_DELAY 90000 /* 1s */
|
||||
#define MPEG_MAX_SCR_INTERVAL 63000 /* 0.7s */
|
||||
|
||||
// suggestions
|
||||
#define MPEG_STARTPTS 45000 /* 0.5s */
|
||||
#define MPEG_MIN_PTS_DELAY 9000 /* 0.1s */
|
||||
#define MPEG_STARTSCR 9 /* 0.1ms */
|
||||
|
||||
//static unsigned int mpeg_min_delay;
|
||||
//static unsigned int mpeg_max_delay;
|
||||
|
||||
static muxer_stream_t* mpegfile_new_stream(muxer_t *muxer,int type){
|
||||
muxer_stream_t *s;
|
||||
|
||||
if(muxer->avih.dwStreams>=MUXER_MAX_STREAMS){
|
||||
printf("Too many streams! increase MUXER_MAX_STREAMS !\n");
|
||||
return NULL;
|
||||
}
|
||||
switch (type) {
|
||||
case MUXER_TYPE_VIDEO:
|
||||
if (muxer->num_videos >= 15) {
|
||||
printf ("MPEG stream can't contain above of 15 video streams!\n");
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case MUXER_TYPE_AUDIO:
|
||||
if (muxer->avih.dwStreams - muxer->num_videos >= 31) {
|
||||
printf ("MPEG stream can't contain above of 31 audio streams!\n");
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf ("Unknown stream type!\n");
|
||||
return NULL;
|
||||
}
|
||||
s=malloc(sizeof(muxer_stream_t));
|
||||
memset(s,0,sizeof(muxer_stream_t));
|
||||
if(!s) return NULL; // no mem!?
|
||||
if (!(s->b_buffer = malloc (MUXER_MPEG_BLOCKSIZE))) {
|
||||
free (s);
|
||||
return NULL; // no mem?!
|
||||
} else if (type == MUXER_TYPE_VIDEO) {
|
||||
s->ckid = be2me_32 (0x1e0 + muxer->num_videos);
|
||||
muxer->num_videos++;
|
||||
s->h.fccType=streamtypeVIDEO;
|
||||
if(!muxer->def_v) muxer->def_v=s;
|
||||
// printf ("Added video stream %d\n", muxer->num_videos);
|
||||
} else { // MUXER_TYPE_AUDIO
|
||||
s->ckid = be2me_32 (0x1c0 + s->id - muxer->num_videos);
|
||||
s->h.fccType=streamtypeAUDIO;
|
||||
// printf ("Added audio stream %d\n", s->id - muxer->num_videos + 1);
|
||||
}
|
||||
muxer->streams[muxer->avih.dwStreams]=s;
|
||||
s->type=type;
|
||||
s->id=muxer->avih.dwStreams;
|
||||
s->timer=0.0;
|
||||
s->size=0;
|
||||
muxer->avih.dwStreams++;
|
||||
return s;
|
||||
}
|
||||
|
||||
static void write_mpeg_ts(unsigned char *b, unsigned int ts, char mod) {
|
||||
b[0] = ((ts >> 29) & 0xf) | 1 | mod;
|
||||
b[1] = (ts >> 22) & 0xff;
|
||||
b[2] = ((ts >> 14) & 0xff) | 1;
|
||||
b[3] = (ts >> 7) & 0xff;
|
||||
b[4] = ((ts << 1) & 0xff) | 1;
|
||||
}
|
||||
|
||||
static void write_mpeg_rate(unsigned char *b, unsigned int rate) {
|
||||
if (rate)
|
||||
rate--; // for round upward
|
||||
rate /= 50;
|
||||
rate++; // round upward
|
||||
b[0] = ((rate >> 15) & 0x7f) | 0x80;
|
||||
b[1] = (rate >> 7) & 0xff;
|
||||
b[2] = ((rate << 1) & 0xff) | 1;
|
||||
}
|
||||
|
||||
static void write_mpeg_std(unsigned char *b, unsigned int size, char mod) {
|
||||
if (size)
|
||||
size--; // for round upward
|
||||
if (size < (128 << 8))
|
||||
size >>= 7; // by 128 bytes
|
||||
else {
|
||||
size >>= 10;
|
||||
size |= 0x2000; // by 1kbyte
|
||||
}
|
||||
size++; // round upward
|
||||
b[0] = ((size >> 8) & 0x3f) | 0x40 | mod;
|
||||
b[1] = size & 0xff;
|
||||
}
|
||||
|
||||
static int write_mpeg_block(muxer_t *muxer, muxer_stream_t *s, FILE *f, char *bl, size_t len, int isoend){
|
||||
size_t sz; // rest in block buffer
|
||||
unsigned char buff[12]; // 0x1ba header
|
||||
unsigned int mints=0;
|
||||
uint16_t l1;
|
||||
|
||||
if (s->b_buffer_ptr == 0) { // 00001111 if no PTS
|
||||
s->b_buffer[0] = 0xf;
|
||||
s->b_buffer_ptr = 1;
|
||||
sz = MUXER_MPEG_DATASIZE-1;
|
||||
} else if (s->b_buffer_ptr > MUXER_MPEG_DATASIZE) {
|
||||
printf ("Unknown error in write_mpeg_block()!\n");
|
||||
return 0;
|
||||
} else {
|
||||
sz = MUXER_MPEG_DATASIZE - s->b_buffer_ptr;
|
||||
if (s->b_buffer[7] == 0xff) // PTS not set yet
|
||||
s->b_buffer[11] = 0xf; // terminate stuFFing bytes
|
||||
}
|
||||
if (len > sz)
|
||||
len = sz;
|
||||
*(uint32_t *)buff = be2me_32 (0x1ba);
|
||||
write_mpeg_ts (buff+4, muxer->file_end, 0x20); // 0010 and SCR
|
||||
write_mpeg_rate (buff+9, muxer->sysrate);
|
||||
fwrite (buff, 12, 1, f);
|
||||
fwrite (&s->ckid, 4, 1, f); // stream_id
|
||||
memset (buff, 0xff, 12); // stuFFing bytes
|
||||
sz -= len;
|
||||
// calculate padding bytes in buffer
|
||||
while (mints < s->b_buffer_ptr && s->b_buffer[mints] == 0xff) mints++;
|
||||
if (mints+sz < 12) { // cannot write padding block so write up to 12 stuFFing bytes
|
||||
l1 = be2me_16 (MUXER_MPEG_DATASIZE);
|
||||
fwrite (&l1, 2, 1, f);
|
||||
mints = 0; // so stuFFed bytes will be written all
|
||||
if (sz)
|
||||
fwrite (buff, sz, 1, f);
|
||||
sz = 0; // no padding block anyway
|
||||
} else { // use padding block
|
||||
if (sz > 6) // sufficient for PAD header so don't shorter data
|
||||
mints = 0;
|
||||
else
|
||||
sz += mints; // skip stuFFing bytes (sz>8 here)
|
||||
l1 = be2me_16 (s->b_buffer_ptr+len-mints);
|
||||
fwrite (&l1, 2, 1, f);
|
||||
}
|
||||
if (s->b_buffer_ptr)
|
||||
fwrite (s->b_buffer+mints, s->b_buffer_ptr-mints, 1, f);
|
||||
if (len)
|
||||
fwrite (bl, len, 1, f);
|
||||
if (sz > 6) { // padding block (0x1be)
|
||||
uint32_t l0;
|
||||
|
||||
if (isoend)
|
||||
l0 = be2me_32 (0x1b9);
|
||||
else
|
||||
l0 = be2me_32 (0x1be);
|
||||
sz -= 6;
|
||||
l1 = be2me_16 (sz);
|
||||
fwrite (&l0, 4, 1, f);
|
||||
fwrite (&l1, 2, 1, f);
|
||||
memset (s->b_buffer, 0xff, sz); // stuFFing bytes
|
||||
fwrite (s->b_buffer, sz, 1, f);
|
||||
}
|
||||
s->b_buffer_ptr = 0;
|
||||
muxer->movi_end += MUXER_MPEG_BLOCKSIZE;
|
||||
// prepare timestamps for next pack
|
||||
mints = (MUXER_MPEG_BLOCKSIZE*90000/muxer->sysrate)+1; // min ts delta
|
||||
sz = (int)(s->timer*90000) + MPEG_STARTPTS; // new PTS
|
||||
if (sz > muxer->file_end)
|
||||
sz -= muxer->file_end; // suggested ts delta
|
||||
else
|
||||
{
|
||||
sz = 0;
|
||||
printf ("Error in stream: PTS earlier than SCR!\n");
|
||||
}
|
||||
if (sz > MPEG_MAX_PTS_DELAY) {
|
||||
// printf ("Warning: attempt to set PTS to SCR delay to %u \n", sz);
|
||||
mints = sz-MPEG_MAX_PTS_DELAY; // try to compensate
|
||||
if (mints > MPEG_MAX_SCR_INTERVAL) {
|
||||
printf ("Error in stream: SCR interval %u is too big!\n", mints);
|
||||
}
|
||||
} else if (sz > 54000) // assume 0.3...0.7s is optimal
|
||||
mints += (sz-45000)>>2; // reach 0.5s in 4 blocks ?
|
||||
else if (sz < 27000) {
|
||||
unsigned int newsysrate = 0;
|
||||
|
||||
if (s->timer > 0.5) // too early to calculate???
|
||||
newsysrate = muxer->movi_end/(s->timer*0.4); // pike-factor 2.5 (8dB)
|
||||
if (sz < MPEG_MIN_PTS_DELAY)
|
||||
printf ("Error in stream: PTS to SCR delay %u is too little!\n", sz);
|
||||
if (muxer->sysrate < newsysrate)
|
||||
muxer->sysrate = newsysrate; // increase next rate to current rate
|
||||
else if (!newsysrate)
|
||||
muxer->sysrate += muxer->sysrate>>3; // increase next rate by 25%
|
||||
}
|
||||
muxer->file_end += mints; // update the system timestamp
|
||||
return len;
|
||||
}
|
||||
|
||||
static void set_mpeg_pts(muxer_t *muxer, muxer_stream_t *s, unsigned int pts) {
|
||||
unsigned int dts, nts;
|
||||
|
||||
if (s->b_buffer_ptr != 0 && s->b_buffer[7] != 0xff)
|
||||
return; // already set
|
||||
if (s->b_buffer_ptr == 0) {
|
||||
memset (s->b_buffer, 0xff, 7); // reserved for PTS or STD, stuFFing for now
|
||||
s->b_buffer_ptr = 12;
|
||||
}
|
||||
dts = (int)(s->timer*90000) + MPEG_STARTPTS; // PTS
|
||||
if (pts) {
|
||||
write_mpeg_ts (s->b_buffer+2, pts, 0x30); // 0011 and both PTS/DTS
|
||||
} else {
|
||||
write_mpeg_ts (s->b_buffer+7, dts, 0x20); // 0010 and PTS only
|
||||
return;
|
||||
}
|
||||
nts = dts - muxer->file_end;
|
||||
// if (nts < mpeg_min_delay) mpeg_min_delay = nts;
|
||||
// if (nts > mpeg_max_delay) mpeg_max_delay = nts;
|
||||
nts = 180000*s->h.dwScale/s->h.dwRate; // two frames
|
||||
if (dts-nts < muxer->file_end) {
|
||||
dts += muxer->file_end;
|
||||
dts /= 2; // calculate average time
|
||||
printf ("Warning: DTS to SCR delay is too small\n");
|
||||
}
|
||||
else
|
||||
dts -= nts/2; // one frame :)
|
||||
write_mpeg_ts (s->b_buffer+7, dts, 0x10);
|
||||
}
|
||||
|
||||
static void mpegfile_write_chunk(muxer_t *muxer,muxer_stream_t *s,FILE *f,size_t len,unsigned int flags){
|
||||
size_t ptr=0, sz;
|
||||
unsigned int pts=0;
|
||||
|
||||
if (s->type == MUXER_TYPE_VIDEO) { // try to recognize frame type...
|
||||
if (s->buffer[0] != 0 || s->buffer[1] != 0 || s->buffer[2] != 1 || len<6) {
|
||||
printf ("Unknown block type, possibly non-MPEG stream!\n");
|
||||
sz = len;
|
||||
// return;
|
||||
} else if (s->buffer[3] == 0 || s->buffer[3] == 0xb3 ||
|
||||
s->buffer[3] == 0xb8) { // Picture or GOP
|
||||
int temp_ref;
|
||||
int pt;
|
||||
|
||||
if (s->buffer[3]) { // GOP -- scan for Picture
|
||||
s->gop_start = s->h.dwLength;
|
||||
while (ptr < len-5 && (s->buffer[ptr] != 0 || s->buffer[ptr+1] != 0 ||
|
||||
s->buffer[ptr+2] != 1 || s->buffer[ptr+3] != 0)) ptr++;
|
||||
if (s->b_buffer_ptr > MUXER_MPEG_DATASIZE-39-12) { // 39 bytes for Gop+Pic+Slice headers
|
||||
write_mpeg_block (muxer, s, f, NULL, 0, 0);
|
||||
}
|
||||
}
|
||||
if (ptr >= len-5) {
|
||||
pt = 0; // Picture not found?!
|
||||
temp_ref = 0;
|
||||
printf ("Warning: picture not found in GOP!\n");
|
||||
} else {
|
||||
pt = (s->buffer[ptr+5]>>3) & 7;
|
||||
temp_ref = (s->buffer[ptr+4]<<2)+(s->buffer[ptr+5]>>6);
|
||||
}
|
||||
ptr = 0;
|
||||
temp_ref += s->gop_start;
|
||||
switch (pt) {
|
||||
case 2: // predictive
|
||||
if (s->ipb[0]) {
|
||||
sz = len + s->ipb[0];
|
||||
if (s->ipb[0] < s->ipb[2])
|
||||
s->ipb[0] = s->ipb[2];
|
||||
s->ipb[2] = 0;
|
||||
} else if (s->ipb[2]) {
|
||||
sz = len + s->ipb[2];
|
||||
s->ipb[0] = s->ipb[2];
|
||||
s->ipb[2] = 0;
|
||||
} else
|
||||
sz = 4 * len; // no bidirectional frames yet?
|
||||
s->ipb[1] = len;
|
||||
// pictires may be not in frame sequence so recalculate timer
|
||||
pts = (int)(90000*((double)temp_ref*s->h.dwScale/s->h.dwRate)) + MPEG_STARTPTS;
|
||||
break;
|
||||
case 3: // bidirectional
|
||||
s->ipb[2] += len;
|
||||
sz = s->ipb[1] + s->ipb[2];
|
||||
// pictires may be not in frame sequence so recalculate timer
|
||||
s->timer = (double)temp_ref*s->h.dwScale/s->h.dwRate;
|
||||
break;
|
||||
default: // intra-coded
|
||||
// pictires may be not in frame sequence so recalculate timer
|
||||
pts = (int)(90000*((double)temp_ref*s->h.dwScale/s->h.dwRate)) + MPEG_STARTPTS;
|
||||
sz = len; // no extra buffer for it...
|
||||
}
|
||||
} else {
|
||||
printf ("Unknown block type, possibly non-MPEG stream!\n");
|
||||
sz = len;
|
||||
// return;
|
||||
}
|
||||
sz <<= 1;
|
||||
} else { // MUXER_TYPE_AUDIO
|
||||
if (len < 2*MUXER_MPEG_DATASIZE)
|
||||
sz = 2*MUXER_MPEG_DATASIZE; // min requirement
|
||||
else
|
||||
sz = len;
|
||||
}
|
||||
set_mpeg_pts (muxer, s, pts);
|
||||
// alter counters:
|
||||
if (s->h.dwSampleSize) {
|
||||
// CBR
|
||||
s->h.dwLength += len/s->h.dwSampleSize;
|
||||
if (len%s->h.dwSampleSize) printf("Warning! len isn't divisable by samplesize!\n");
|
||||
} else {
|
||||
// VBR
|
||||
s->h.dwLength++;
|
||||
}
|
||||
if (!muxer->sysrate) {
|
||||
muxer->sysrate = 2108000/8; // constrained stream parameter
|
||||
muxer->file_end = MUXER_MPEG_BLOCKSIZE*90000/muxer->sysrate + MPEG_STARTSCR+1;
|
||||
}
|
||||
if (sz > s->h.dwSuggestedBufferSize) { // increase and set STD
|
||||
s->h.dwSuggestedBufferSize = sz;
|
||||
if (s->b_buffer[2] != 0xff) // has both PTS and DTS
|
||||
write_mpeg_std (s->b_buffer, s->h.dwSuggestedBufferSize, 0x40); // 01
|
||||
else // has only PTS
|
||||
write_mpeg_std (s->b_buffer+5, s->h.dwSuggestedBufferSize, 0x40); // 01
|
||||
}
|
||||
s->size += len;
|
||||
// write out block(s) if it's ready
|
||||
while (s->b_buffer_ptr+len >= MUXER_MPEG_DATASIZE-12) { // reserved for std and pts
|
||||
// write out the block
|
||||
sz = write_mpeg_block (muxer, s, f, &s->buffer[ptr], len, 0);
|
||||
// recalculate the rest of chunk
|
||||
ptr += sz;
|
||||
len -= sz;
|
||||
}
|
||||
s->timer = (double)s->h.dwLength*s->h.dwScale/s->h.dwRate;
|
||||
if (len) { // save rest in buffer
|
||||
if (s->b_buffer_ptr == 0) {
|
||||
memset (s->b_buffer, 0xff, 12); // stuFFing bytes for now
|
||||
if (s->type == MUXER_TYPE_AUDIO && s->h.dwSampleSize) { // CBR audio
|
||||
sz = s->h.dwLength - len/s->h.dwSampleSize; // first sample number
|
||||
write_mpeg_ts (s->b_buffer+7,
|
||||
(int)(90000*((double)sz*s->h.dwScale/s->h.dwRate)) + MPEG_STARTPTS,
|
||||
0x20); // 0010 and PTS only
|
||||
}
|
||||
s->b_buffer_ptr = 12;
|
||||
}
|
||||
memcpy (s->b_buffer+s->b_buffer_ptr, s->buffer+ptr, len);
|
||||
s->b_buffer_ptr += len;
|
||||
}
|
||||
}
|
||||
|
||||
static void mpegfile_write_header(muxer_t *muxer,FILE *f){
|
||||
unsigned int i;
|
||||
size_t sz = MUXER_MPEG_BLOCKSIZE-24;
|
||||
unsigned char buff[12];
|
||||
muxer_stream_t *s = muxer->streams[0];
|
||||
uint32_t l1;
|
||||
uint16_t l2;
|
||||
|
||||
if (s == NULL)
|
||||
return; // no streams!?
|
||||
// packet header (0x1ba) -- rewrite first stream buffer
|
||||
*(uint32_t *)buff = be2me_32 (0x1ba);
|
||||
write_mpeg_ts (buff+4, MPEG_STARTSCR, 0x20); // 0010 -- pack
|
||||
write_mpeg_rate (buff+9, muxer->sysrate);
|
||||
fwrite (buff, 12, 1, f);
|
||||
// start system stream (in own block): Sys (0x1bb)
|
||||
l1 = be2me_32 (0x1bb);
|
||||
l2 = be2me_16 (6 + 3*muxer->avih.dwStreams); // header_length
|
||||
fwrite (&l1, 4, 1, f);
|
||||
fwrite (&l2, 2, 1, f);
|
||||
write_mpeg_rate (buff, muxer->sysrate); // rate_bound
|
||||
// set number of audio/video, fixed_flag=CSPS_flag=system_*_lock_flag=0
|
||||
buff[3] = (muxer->avih.dwStreams - muxer->num_videos) << 2; // audio_bound
|
||||
buff[4] = muxer->num_videos | 0x20;
|
||||
buff[5] = 0xff; // reserved_byte
|
||||
fwrite (buff, 6, 1, f);
|
||||
for (i = 0; i < muxer->avih.dwStreams; i++) {
|
||||
buff[0] = ((char *)&muxer->streams[i]->ckid)[3]; // last char in big endian
|
||||
//fprintf (stderr, "... stream 0x1%02x; bufsize %u", (int)buff[0], muxer->streams[i]->h.dwSuggestedBufferSize);
|
||||
write_mpeg_std (buff+1, muxer->streams[i]->h.dwSuggestedBufferSize, 0xc0); // 11
|
||||
fwrite (buff, 3, 1, f);
|
||||
sz -= 3;
|
||||
}
|
||||
if (sz >= 6) { // padding block
|
||||
l1 = be2me_32 (0x1be);
|
||||
sz -= 6;
|
||||
l2 = be2me_16 (sz);
|
||||
fwrite (&l1, 4, 1, f);
|
||||
fwrite (&l2, 2, 1, f);
|
||||
}
|
||||
s->b_buffer[0] = 0x0f; // end of list - next bit has to be 0
|
||||
// stuFFing bytes -- rewrite first stream buffer
|
||||
if (sz > 1)
|
||||
memset (s->b_buffer+1, 0xff, sz-1);
|
||||
fwrite (s->b_buffer, sz, 1, f);
|
||||
muxer->movi_start = 0;
|
||||
muxer->movi_end = MUXER_MPEG_BLOCKSIZE;
|
||||
}
|
||||
|
||||
static void mpegfile_write_index(muxer_t *muxer,FILE *f){
|
||||
unsigned int i;
|
||||
unsigned int rsr;
|
||||
|
||||
if (!muxer->avih.dwStreams) return; // no streams?!
|
||||
// finish all but one video and audio streams
|
||||
rsr = muxer->sysrate; // reserve it since it's silly change it at that point
|
||||
for (i = 0; i < muxer->avih.dwStreams-1; i++)
|
||||
write_mpeg_block (muxer, muxer->streams[i], f, NULL, 0, 0);
|
||||
// end sequence: ISO-11172-End (0x1b9) and finish very last block
|
||||
write_mpeg_block (muxer, muxer->streams[i], f, NULL, 0, 1);
|
||||
//fprintf (stderr, "PTS to SCR delay: min %u.%03u, max %u.%03u\n",
|
||||
// mpeg_min_delay/90000, (mpeg_min_delay/90)%1000,
|
||||
// mpeg_max_delay/90000, (mpeg_max_delay/90)%1000);
|
||||
muxer->sysrate = rsr;
|
||||
}
|
||||
|
||||
void muxer_init_muxer_mpeg(muxer_t *muxer){
|
||||
muxer->cont_new_stream = &mpegfile_new_stream;
|
||||
muxer->cont_write_chunk = &mpegfile_write_chunk;
|
||||
muxer->cont_write_header = &mpegfile_write_header;
|
||||
muxer->cont_write_index = &mpegfile_write_index;
|
||||
// mpeg_min_delay = mpeg_max_delay = MPEG_STARTPTS-MPEG_STARTSCR;
|
||||
}
|
||||
|
48
mencoder.c
48
mencoder.c
@ -47,7 +47,7 @@ static char* banner_text=
|
||||
#include "libmpdemux/demuxer.h"
|
||||
#include "libmpdemux/stheader.h"
|
||||
#include "libmpdemux/mp3_hdr.h"
|
||||
#include "libmpdemux/aviwrite.h"
|
||||
#include "libmpdemux/muxer.h"
|
||||
|
||||
|
||||
#include "libvo/video_out.h"
|
||||
@ -108,6 +108,8 @@ static char** video_fm_list=NULL; // override video codec family
|
||||
static int out_audio_codec=-1;
|
||||
static int out_video_codec=-1;
|
||||
|
||||
int out_file_format=MUXER_TYPE_AVI; // default to AVI
|
||||
|
||||
// audio stream skip/resync functions requires only for seeking.
|
||||
// (they should be implemented in the audio codec layer)
|
||||
//void skip_audio_frame(sh_audio_t *sh_audio){}
|
||||
@ -301,12 +303,12 @@ static void exit_sighandler(int x){
|
||||
interrupted=1;
|
||||
}
|
||||
|
||||
static aviwrite_t* muxer=NULL;
|
||||
static muxer_t* muxer=NULL;
|
||||
static FILE* muxer_f=NULL;
|
||||
|
||||
// callback for ve_*.c:
|
||||
void mencoder_write_chunk(aviwrite_stream_t *s,int len,unsigned int flags){
|
||||
aviwrite_write_chunk(muxer,s,muxer_f,len,flags);
|
||||
void mencoder_write_chunk(muxer_stream_t *s,int len,unsigned int flags){
|
||||
muxer_write_chunk(muxer,s,muxer_f,len,flags);
|
||||
}
|
||||
|
||||
extern void print_wave_header(WAVEFORMATEX *h);
|
||||
@ -335,8 +337,8 @@ uint32_t skippedframes=0;
|
||||
uint32_t duplicatedframes=0;
|
||||
uint32_t badframes=0;
|
||||
|
||||
aviwrite_stream_t* mux_a=NULL;
|
||||
aviwrite_stream_t* mux_v=NULL;
|
||||
muxer_stream_t* mux_a=NULL;
|
||||
muxer_stream_t* mux_v=NULL;
|
||||
off_t muxer_f_size=0;
|
||||
|
||||
#ifdef HAVE_MP3LAME
|
||||
@ -600,11 +602,11 @@ if(!muxer_f) {
|
||||
mencoder_exit(1,NULL);
|
||||
}
|
||||
|
||||
muxer=aviwrite_new_muxer();
|
||||
muxer=muxer_new_muxer(out_file_format);
|
||||
|
||||
// ============= VIDEO ===============
|
||||
|
||||
mux_v=aviwrite_new_stream(muxer,AVIWRITE_TYPE_VIDEO);
|
||||
mux_v=muxer_new_stream(muxer,MUXER_TYPE_VIDEO);
|
||||
|
||||
mux_v->buffer_size=0x200000; // 2MB
|
||||
mux_v->buffer=malloc(mux_v->buffer_size);
|
||||
@ -698,7 +700,7 @@ if ((force_fourcc != NULL) && (strlen(force_fourcc) >= 4))
|
||||
// ============= AUDIO ===============
|
||||
if(sh_audio){
|
||||
|
||||
mux_a=aviwrite_new_stream(muxer,AVIWRITE_TYPE_AUDIO);
|
||||
mux_a=muxer_new_stream(muxer,MUXER_TYPE_AUDIO);
|
||||
|
||||
mux_a->buffer_size=0x100000; //16384;
|
||||
mux_a->buffer=malloc(mux_a->buffer_size);
|
||||
@ -809,7 +811,7 @@ if(audio_delay!=0.0){
|
||||
} // if(sh_audio)
|
||||
|
||||
printf(MSGTR_WritingAVIHeader);
|
||||
aviwrite_write_header(muxer,muxer_f);
|
||||
muxer_write_header(muxer,muxer_f);
|
||||
|
||||
decoded_frameno=0;
|
||||
|
||||
@ -877,6 +879,18 @@ if (seek_to_sec) {
|
||||
// if(demuxer2) demux_seek(demuxer2, d, 1);
|
||||
}
|
||||
|
||||
if (out_file_format == MUXER_TYPE_MPEG)
|
||||
{
|
||||
if (audio_preload > 0.4) {
|
||||
fprintf(stderr,"Limiting audio preload to 0.4s\n");
|
||||
audio_preload = 0.4;
|
||||
}
|
||||
if (audio_density < 4) {
|
||||
fprintf(stderr,"Increasing audio density to 4\n");
|
||||
audio_preload = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if(tv_param_on == 1)
|
||||
{
|
||||
fprintf(stderr,"Forcing audio preload to 0, max pts correction to 0\n");
|
||||
@ -983,7 +997,7 @@ if(sh_audio){
|
||||
}
|
||||
}
|
||||
if(len<=0) break; // EOF?
|
||||
aviwrite_write_chunk(muxer,mux_a,muxer_f,len,0x10);
|
||||
muxer_write_chunk(muxer,mux_a,muxer_f,len,0x10);
|
||||
if(!mux_a->h.dwSampleSize && mux_a->timer>0)
|
||||
mux_a->wf->nAvgBytesPerSec=0.5f+(double)mux_a->size/mux_a->timer; // avg bps (VBR)
|
||||
if(mux_a->buffer_len>=len){
|
||||
@ -1063,11 +1077,11 @@ ptimer_start = GetTimerMS();
|
||||
switch(mux_v->codec){
|
||||
case VCODEC_COPY:
|
||||
mux_v->buffer=start;
|
||||
if(skip_flag<=0) aviwrite_write_chunk(muxer,mux_v,muxer_f,in_size,(sh_video->ds->flags&1)?0x10:0);
|
||||
if(skip_flag<=0) muxer_write_chunk(muxer,mux_v,muxer_f,in_size,(sh_video->ds->flags&1)?0x10:0);
|
||||
break;
|
||||
case VCODEC_FRAMENO:
|
||||
mux_v->buffer=(unsigned char *)&decoded_frameno; // tricky
|
||||
if(skip_flag<=0) aviwrite_write_chunk(muxer,mux_v,muxer_f,sizeof(int),0x10);
|
||||
if(skip_flag<=0) muxer_write_chunk(muxer,mux_v,muxer_f,sizeof(int),0x10);
|
||||
break;
|
||||
default:
|
||||
// decode_video will callback down to ve_*.c encoders, through the video filters
|
||||
@ -1078,7 +1092,7 @@ default:
|
||||
// unwanted skipping of a frame, what to do?
|
||||
if(skip_limit==0){
|
||||
// skipping not allowed -> write empty frame:
|
||||
aviwrite_write_chunk(muxer,mux_v,muxer_f,0,0);
|
||||
muxer_write_chunk(muxer,mux_v,muxer_f,0,0);
|
||||
} else {
|
||||
// skipping allowed -> skip it and distriubute timer error:
|
||||
v_timer_corr-=(float)mux_v->h.dwScale/mux_v->h.dwRate;
|
||||
@ -1095,7 +1109,7 @@ if(skip_flag<0){
|
||||
if(!tv_param_on && !verbose) printf(MSGTR_DuplicateFrames,-skip_flag);
|
||||
while(skip_flag<0){
|
||||
duplicatedframes++;
|
||||
aviwrite_write_chunk(muxer,mux_v,muxer_f,0,0);
|
||||
muxer_write_chunk(muxer,mux_v,muxer_f,0,0);
|
||||
++skip_flag;
|
||||
}
|
||||
} else
|
||||
@ -1254,11 +1268,11 @@ if(sh_audio && mux_a->codec==ACODEC_VBRMP3 && !lame_param_vbr){
|
||||
#endif
|
||||
|
||||
printf(MSGTR_WritingAVIIndex);
|
||||
aviwrite_write_index(muxer,muxer_f);
|
||||
muxer_write_index(muxer,muxer_f);
|
||||
muxer_f_size=ftello(muxer_f);
|
||||
printf(MSGTR_FixupAVIHeader);
|
||||
fseek(muxer_f,0,SEEK_SET);
|
||||
aviwrite_write_header(muxer,muxer_f); // update header
|
||||
muxer_write_header(muxer,muxer_f); // update header
|
||||
if(ferror(muxer_f) || fclose(muxer_f) != 0) {
|
||||
mp_msg(MSGT_MENCODER,MSGL_FATAL,MSGTR_ErrorWritingFile, out_filename);
|
||||
mencoder_exit(1, NULL);
|
||||
|
Loading…
Reference in New Issue
Block a user