mirror of https://github.com/mpv-player/mpv
OpenDML read/write support
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@12037 b3059339-0415-0410-9bf9-f77b7e298cf2
This commit is contained in:
parent
6080f08560
commit
873b579c1a
4
AUTHORS
4
AUTHORS
|
@ -260,6 +260,7 @@ Tobias Diedrich <ranma@gmx.at>
|
||||||
* DXR2 driver
|
* DXR2 driver
|
||||||
* softpulldown video filter
|
* softpulldown video filter
|
||||||
* ported Donald Graft's kerndeint video filter
|
* ported Donald Graft's kerndeint video filter
|
||||||
|
* AVI OpenDML write support
|
||||||
|
|
||||||
Kilian A. Foth <foth@informatik.uni-hamburg.de>
|
Kilian A. Foth <foth@informatik.uni-hamburg.de>
|
||||||
* -slave mode
|
* -slave mode
|
||||||
|
@ -623,6 +624,9 @@ Jake Janovetz
|
||||||
Vivien Chappelier, Damien Vincent
|
Vivien Chappelier, Damien Vincent
|
||||||
* libFAME authors [fast mpeg-1 encoder, used by -vo mpegpes/-vo dxr3]
|
* libFAME authors [fast mpeg-1 encoder, used by -vo mpegpes/-vo dxr3]
|
||||||
|
|
||||||
|
Tilmann Bitterberg
|
||||||
|
* AVI OpenDML read support
|
||||||
|
|
||||||
_____________________________________________________
|
_____________________________________________________
|
||||||
Their code is not used in the current player version,
|
Their code is not used in the current player version,
|
||||||
but I've got some ideas or other technical help from:
|
but I've got some ideas or other technical help from:
|
||||||
|
|
|
@ -817,7 +817,7 @@ Further, MPlayer won't prevent you from loading an index file generated
|
||||||
from a different AVI, but this is sure to cause unfavorable results.
|
from a different AVI, but this is sure to cause unfavorable results.
|
||||||
.br
|
.br
|
||||||
.I NOTE:
|
.I NOTE:
|
||||||
This option will be obsoleted once AVI gets ODML support!
|
This option is obsolete, because MPlayer has OpenDML support.
|
||||||
.TP
|
.TP
|
||||||
.B \-mc <seconds/frame>
|
.B \-mc <seconds/frame>
|
||||||
Maximum A-V sync correction per frame (in seconds).
|
Maximum A-V sync correction per frame (in seconds).
|
||||||
|
@ -926,20 +926,9 @@ not pass incoming UDP packets (see http://www.live.com/mplayer/).
|
||||||
Force rebuilding of INDEX and output to a separate file specified by the
|
Force rebuilding of INDEX and output to a separate file specified by the
|
||||||
argument filename.
|
argument filename.
|
||||||
Currently this only works with AVI files.
|
Currently this only works with AVI files.
|
||||||
Although you can use MEncoder to fix files without indexes, the AVI
|
|
||||||
container format is limited to indexing files up to 2GB in size.
|
|
||||||
It is however possible to store the index in a separate file and use it later
|
|
||||||
with \-loadidx, which is faster than rebuilding the index (with \-idx or
|
|
||||||
\-forceidx) each time the movie is opened.
|
|
||||||
(This is a limitation of the AVI format, and although there exists an
|
|
||||||
extension to index beyond 2GB, MPlayer doesn't yet support this extension.)
|
|
||||||
After the index file is created, MPlayer will begin to play the video.
|
|
||||||
If you want to automate index file generation (after encoding a large file
|
|
||||||
off a TV capture card, for example), you can specify \-frames 0 to
|
|
||||||
prevent MPlayer from playing the video after generating the index.
|
|
||||||
.br
|
.br
|
||||||
.I NOTE:
|
.I NOTE:
|
||||||
This option will be obsoleted once AVI gets ODML support!
|
This option is obsolete, because MPlayer has OpenDML support.
|
||||||
.TP
|
.TP
|
||||||
.B \-sb <byte\ position> (see \-ss option too)
|
.B \-sb <byte\ position> (see \-ss option too)
|
||||||
Seek to byte position.
|
Seek to byte position.
|
||||||
|
|
|
@ -25,6 +25,48 @@ extern void print_strh(AVIStreamHeader *h);
|
||||||
extern void print_wave_header(WAVEFORMATEX *h);
|
extern void print_wave_header(WAVEFORMATEX *h);
|
||||||
extern void print_video_header(BITMAPINFOHEADER *h);
|
extern void print_video_header(BITMAPINFOHEADER *h);
|
||||||
extern void print_index(AVIINDEXENTRY *idx,int idx_size);
|
extern void print_index(AVIINDEXENTRY *idx,int idx_size);
|
||||||
|
extern void print_avistdindex_chunk(avistdindex_chunk *h);
|
||||||
|
extern void print_avisuperindex_chunk(avisuperindex_chunk *h);
|
||||||
|
|
||||||
|
static int odml_get_vstream_id(int id, unsigned char res[])
|
||||||
|
{
|
||||||
|
unsigned char *p = (unsigned char *)&id;
|
||||||
|
id = le2me_32(id);
|
||||||
|
|
||||||
|
if (p[2] == 'd') {
|
||||||
|
if (res) {
|
||||||
|
res[0] = p[0];
|
||||||
|
res[1] = p[1];
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Simple quicksort for AVIINDEXENTRYs
|
||||||
|
*/
|
||||||
|
static void avi_idx_quicksort(AVIINDEXENTRY *idx, int from, int to)
|
||||||
|
{
|
||||||
|
AVIINDEXENTRY temp;
|
||||||
|
int lo = to;
|
||||||
|
int hi = from;
|
||||||
|
off_t pivot_ofs = AVI_IDX_OFFSET(&idx[(from + to) / 2]);
|
||||||
|
do {
|
||||||
|
while(pivot_ofs < AVI_IDX_OFFSET(&idx[lo])) lo--;
|
||||||
|
while(pivot_ofs > AVI_IDX_OFFSET(&idx[hi])) hi++;
|
||||||
|
if(hi <= lo) {
|
||||||
|
if (hi != lo) {
|
||||||
|
memcpy(&temp, &idx[lo], sizeof(temp));
|
||||||
|
memcpy(&idx[lo], &idx[hi], sizeof(temp));
|
||||||
|
memcpy(&idx[hi], &temp, sizeof(temp));
|
||||||
|
}
|
||||||
|
lo--; hi++;
|
||||||
|
}
|
||||||
|
} while (lo >= hi);
|
||||||
|
if (from < lo) avi_idx_quicksort(idx, from, lo);
|
||||||
|
if (to > hi) avi_idx_quicksort(idx, hi, to);
|
||||||
|
}
|
||||||
|
|
||||||
void read_avi_header(demuxer_t *demuxer,int index_mode){
|
void read_avi_header(demuxer_t *demuxer,int index_mode){
|
||||||
sh_audio_t *sh_audio=NULL;
|
sh_audio_t *sh_audio=NULL;
|
||||||
|
@ -178,6 +220,47 @@ while(1){
|
||||||
}
|
}
|
||||||
last_fccType=h.fccType;
|
last_fccType=h.fccType;
|
||||||
if(verbose>=1) print_strh(&h);
|
if(verbose>=1) print_strh(&h);
|
||||||
|
break; }
|
||||||
|
case mmioFOURCC('i', 'n', 'd', 'x'): {
|
||||||
|
DWORD i;
|
||||||
|
unsigned msize = 0;
|
||||||
|
avisuperindex_chunk *s;
|
||||||
|
priv->suidx_size++;
|
||||||
|
priv->suidx = realloc(priv->suidx, priv->suidx_size * sizeof (avisuperindex_chunk));
|
||||||
|
s = &priv->suidx[priv->suidx_size-1];
|
||||||
|
|
||||||
|
chunksize-=24;
|
||||||
|
memcpy(s->fcc, "indx", 4);
|
||||||
|
s->dwSize = size2;
|
||||||
|
s->wLongsPerEntry = stream_read_word_le(demuxer->stream);
|
||||||
|
s->bIndexSubType = stream_read_char(demuxer->stream);
|
||||||
|
s->bIndexType = stream_read_char(demuxer->stream);
|
||||||
|
s->nEntriesInUse = stream_read_dword_le(demuxer->stream);
|
||||||
|
*(uint32_t *)s->dwChunkId = stream_read_dword_le(demuxer->stream);
|
||||||
|
stream_read(demuxer->stream, (char *)s->dwReserved, 3*4);
|
||||||
|
memset(s->dwReserved, 0, 3*4);
|
||||||
|
|
||||||
|
print_avisuperindex_chunk(s);
|
||||||
|
|
||||||
|
msize = sizeof (uint32_t) * s->wLongsPerEntry * s->nEntriesInUse;
|
||||||
|
s->aIndex = malloc(msize);
|
||||||
|
memset (s->aIndex, 0, msize);
|
||||||
|
s->stdidx = malloc (s->nEntriesInUse * sizeof (avistdindex_chunk));
|
||||||
|
memset (s->stdidx, 0, s->nEntriesInUse * sizeof (avistdindex_chunk));
|
||||||
|
|
||||||
|
// now the real index of indices
|
||||||
|
for (i=0; i<s->nEntriesInUse; i++) {
|
||||||
|
chunksize-=16;
|
||||||
|
s->aIndex[i].qwOffset = stream_read_dword_le(demuxer->stream) & 0xffffffff;
|
||||||
|
s->aIndex[i].qwOffset |= ((uint64_t)stream_read_dword_le(demuxer->stream) & 0xffffffff)<<32;
|
||||||
|
s->aIndex[i].dwSize = stream_read_dword_le(demuxer->stream);
|
||||||
|
s->aIndex[i].dwDuration = stream_read_dword_le(demuxer->stream);
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, "ODML (%.4s): [%d] 0x%016llx 0x%04lx %ld\n",
|
||||||
|
(s->dwChunkId), i,
|
||||||
|
(uint64_t)s->aIndex[i].qwOffset, s->aIndex[i].dwSize, s->aIndex[i].dwDuration);
|
||||||
|
}
|
||||||
|
priv->isodml++;
|
||||||
|
|
||||||
break; }
|
break; }
|
||||||
case ckidSTREAMFORMAT: { // read 'strf'
|
case ckidSTREAMFORMAT: { // read 'strf'
|
||||||
if(last_fccType==streamtypeVIDEO){
|
if(last_fccType==streamtypeVIDEO){
|
||||||
|
@ -246,11 +329,41 @@ while(1){
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case mmioFOURCC('v', 'p', 'r', 'p'): {
|
||||||
|
VideoPropHeader *vprp = malloc(chunksize);
|
||||||
|
int i;
|
||||||
|
stream_read(demuxer->stream, (void*)vprp, chunksize);
|
||||||
|
le2me_VideoPropHeader(vprp);
|
||||||
|
chunksize -= sizeof(*vprp)-sizeof(vprp->FieldInfo);
|
||||||
|
chunksize /= sizeof(VIDEO_FIELD_DESC);
|
||||||
|
if (vprp->nbFieldPerFrame > chunksize) {
|
||||||
|
vprp->nbFieldPerFrame = chunksize;
|
||||||
|
}
|
||||||
|
chunksize = 0;
|
||||||
|
for (i=0; i<vprp->nbFieldPerFrame; i++) {
|
||||||
|
le2me_VIDEO_FIELD_DESC(&vprp->FieldInfo[i]);
|
||||||
|
}
|
||||||
|
if (sh_video) {
|
||||||
|
sh_video->aspect = GET_AVI_ASPECT(vprp->dwFrameAspectRatio);
|
||||||
|
}
|
||||||
|
if(verbose>=1) print_vprp(vprp);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case mmioFOURCC('d', 'm', 'l', 'h'): {
|
||||||
|
// dmlh 00 00 00 04 frms
|
||||||
|
unsigned int total_frames = stream_read_dword_le(demuxer->stream);
|
||||||
|
mp_msg(MSGT_HEADER,MSGL_V,"AVI: dmlh found (size=%d) (total_frames=%d)\n", chunksize, total_frames);
|
||||||
|
stream_skip(demuxer->stream, chunksize-4);
|
||||||
|
chunksize = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ckidAVINEWINDEX:
|
case ckidAVINEWINDEX:
|
||||||
if(demuxer->movi_end>stream_tell(demuxer->stream))
|
if(demuxer->movi_end>stream_tell(demuxer->stream))
|
||||||
demuxer->movi_end=stream_tell(demuxer->stream); // fixup movi-end
|
demuxer->movi_end=stream_tell(demuxer->stream); // fixup movi-end
|
||||||
if(index_mode){
|
if(index_mode && !priv->isodml){
|
||||||
int i;
|
int i;
|
||||||
|
off_t base = 0;
|
||||||
|
uint32_t last_off = 0;
|
||||||
priv->idx_size=size2>>4;
|
priv->idx_size=size2>>4;
|
||||||
mp_msg(MSGT_HEADER,MSGL_V,"Reading INDEX block, %d chunks for %ld frames (fpos=%p)\n",
|
mp_msg(MSGT_HEADER,MSGL_V,"Reading INDEX block, %d chunks for %ld frames (fpos=%p)\n",
|
||||||
priv->idx_size,avih.dwTotalFrames, stream_tell(demuxer->stream));
|
priv->idx_size,avih.dwTotalFrames, stream_tell(demuxer->stream));
|
||||||
|
@ -261,8 +374,21 @@ while(1){
|
||||||
le2me_AVIINDEXENTRY((AVIINDEXENTRY*)priv->idx + i);
|
le2me_AVIINDEXENTRY((AVIINDEXENTRY*)priv->idx + i);
|
||||||
chunksize-=priv->idx_size<<4;
|
chunksize-=priv->idx_size<<4;
|
||||||
if(verbose>=2) print_index(priv->idx,priv->idx_size);
|
if(verbose>=2) print_index(priv->idx,priv->idx_size);
|
||||||
break;
|
/*
|
||||||
|
* Fixup index for files >4GB
|
||||||
|
*/
|
||||||
|
for (i = 0; i < priv->idx_size; i++) {
|
||||||
|
AVIINDEXENTRY *idx = (AVIINDEXENTRY*)priv->idx + i;
|
||||||
|
idx->dwFlags &= 0xffff;
|
||||||
|
if (idx->dwChunkOffset < last_off) {
|
||||||
|
mp_msg(MSGT_HEADER,MSGL_WARN,"Index offset going backwards (last=%08X, now=%08X), compensating...\n", last_off, idx->dwChunkOffset);
|
||||||
|
base += 0x100000000LL;
|
||||||
|
}
|
||||||
|
idx->dwFlags |= base >> 16;
|
||||||
|
last_off = idx->dwChunkOffset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
/* added May 2002 */
|
/* added May 2002 */
|
||||||
case mmioFOURCC('R','I','F','F'): {
|
case mmioFOURCC('R','I','F','F'): {
|
||||||
char riff_type[4];
|
char riff_type[4];
|
||||||
|
@ -275,6 +401,10 @@ while(1){
|
||||||
chunksize = 0;
|
chunksize = 0;
|
||||||
list_end = 0; /* a new list will follow */
|
list_end = 0; /* a new list will follow */
|
||||||
break; }
|
break; }
|
||||||
|
case ckidAVIPADDING:
|
||||||
|
stream_skip(demuxer->stream, chunksize);
|
||||||
|
chunksize = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if(hdr){
|
if(hdr){
|
||||||
mp_msg(MSGT_HEADER,MSGL_V,"hdr=%s size=%u\n",hdr,size2);
|
mp_msg(MSGT_HEADER,MSGL_V,"hdr=%s size=%u\n",hdr,size2);
|
||||||
|
@ -293,6 +423,8 @@ while(1){
|
||||||
mp_msg(MSGT_HEADER,MSGL_DBG2,"list_end=0x%X pos=0x%X chunksize=0x%X next=0x%X\n",
|
mp_msg(MSGT_HEADER,MSGL_DBG2,"list_end=0x%X pos=0x%X chunksize=0x%X next=0x%X\n",
|
||||||
(int)list_end, (int)stream_tell(demuxer->stream),
|
(int)list_end, (int)stream_tell(demuxer->stream),
|
||||||
chunksize, (int)chunksize+stream_tell(demuxer->stream));
|
chunksize, (int)chunksize+stream_tell(demuxer->stream));
|
||||||
|
if(list_end>0 &&
|
||||||
|
chunksize+stream_tell(demuxer->stream) == list_end) list_end=0;
|
||||||
if(list_end>0 && chunksize+stream_tell(demuxer->stream)>list_end){
|
if(list_end>0 && chunksize+stream_tell(demuxer->stream)>list_end){
|
||||||
mp_msg(MSGT_HEADER,MSGL_V,"Broken chunk? chunksize=%d (id=%.4s)\n",chunksize,(char *) &id);
|
mp_msg(MSGT_HEADER,MSGL_V,"Broken chunk? chunksize=%d (id=%.4s)\n",chunksize,(char *) &id);
|
||||||
stream_seek(demuxer->stream,list_end);
|
stream_seek(demuxer->stream,list_end);
|
||||||
|
@ -303,6 +435,133 @@ while(1){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (priv->isodml && (index_mode==-1 || index_mode==0)) {
|
||||||
|
int i, j, k;
|
||||||
|
int safety=1000;
|
||||||
|
|
||||||
|
avisuperindex_chunk *cx;
|
||||||
|
AVIINDEXENTRY *idx;
|
||||||
|
|
||||||
|
|
||||||
|
if (priv->idx_size) free(priv->idx);
|
||||||
|
priv->idx_size = 0;
|
||||||
|
priv->idx_offset = 0;
|
||||||
|
priv->idx = NULL;
|
||||||
|
|
||||||
|
mp_msg(MSGT_HEADER, MSGL_INFO,
|
||||||
|
"AVI: ODML: Building odml index (%d superindexchunks)\n", priv->suidx_size);
|
||||||
|
|
||||||
|
// read the standard indices
|
||||||
|
for (cx = &priv->suidx[0], i=0; i<priv->suidx_size; cx++, i++) {
|
||||||
|
stream_reset(demuxer->stream);
|
||||||
|
for (j=0; j<cx->nEntriesInUse; j++) {
|
||||||
|
int ret1, ret2;
|
||||||
|
memset(&cx->stdidx[j], 0, 32);
|
||||||
|
ret1 = stream_seek(demuxer->stream, (off_t)cx->aIndex[j].qwOffset);
|
||||||
|
ret2 = stream_read(demuxer->stream, (char *)&cx->stdidx[j], 32);
|
||||||
|
if (ret1 != 1 || ret2 != 32 || cx->stdidx[j].nEntriesInUse==0) {
|
||||||
|
// this is a broken file (probably incomplete) let the standard
|
||||||
|
// gen_index routine handle this
|
||||||
|
priv->isodml = 0;
|
||||||
|
priv->idx_size = 0;
|
||||||
|
mp_msg(MSGT_HEADER, MSGL_WARN,
|
||||||
|
"AVI: ODML: Broken (incomplete?) file detected. Will use traditional index\n");
|
||||||
|
goto freeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
le2me_AVISTDIDXCHUNK(&cx->stdidx[j]);
|
||||||
|
print_avistdindex_chunk(&cx->stdidx[j]);
|
||||||
|
priv->idx_size += cx->stdidx[j].nEntriesInUse;
|
||||||
|
cx->stdidx[j].aIndex = malloc(cx->stdidx[j].nEntriesInUse*sizeof(avistdindex_entry));
|
||||||
|
stream_read(demuxer->stream, (char *)cx->stdidx[j].aIndex,
|
||||||
|
cx->stdidx[j].nEntriesInUse*sizeof(avistdindex_entry));
|
||||||
|
for (k=0;k<cx->stdidx[j].nEntriesInUse; k++)
|
||||||
|
le2me_AVISTDIDXENTRY(&cx->stdidx[j].aIndex[k]);
|
||||||
|
|
||||||
|
cx->stdidx[j].dwReserved3 = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We convert the index by translating all entries into AVIINDEXENTRYs
|
||||||
|
* and sorting them by offset. The result should be the same index
|
||||||
|
* we would get with -forceidx.
|
||||||
|
*/
|
||||||
|
|
||||||
|
idx = priv->idx = malloc(priv->idx_size * sizeof (AVIINDEXENTRY));
|
||||||
|
|
||||||
|
for (cx = priv->suidx; cx != &priv->suidx[priv->suidx_size]; cx++) {
|
||||||
|
avistdindex_chunk *sic;
|
||||||
|
for (sic = cx->stdidx; sic != &cx->stdidx[cx->nEntriesInUse]; sic++) {
|
||||||
|
avistdindex_entry *sie;
|
||||||
|
for (sie = sic->aIndex; sie != &sic->aIndex[sic->nEntriesInUse]; sie++) {
|
||||||
|
uint64_t off = sic->qwBaseOffset + sie->dwOffset - 8;
|
||||||
|
memcpy(&idx->ckid, sic->dwChunkId, 4);
|
||||||
|
idx->dwChunkOffset = off;
|
||||||
|
idx->dwFlags = (off >> 32) << 16;
|
||||||
|
idx->dwChunkLength = sie->dwSize & 0x7fffffff;
|
||||||
|
idx->dwFlags |= (sie->dwSize&0x80000000)?0x0:AVIIF_KEYFRAME; // bit 31 denotes !keyframe
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
avi_idx_quicksort(priv->idx, 0, priv->idx_size-1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Hack to work around a "wrong" index in some divx odml files
|
||||||
|
(processor_burning.avi as an example)
|
||||||
|
They have ##dc on non keyframes but the ix00 tells us they are ##db.
|
||||||
|
Read the fcc of a non-keyframe vid frame and check it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
{
|
||||||
|
uint32_t id;
|
||||||
|
uint32_t db = 0;
|
||||||
|
stream_reset (demuxer->stream);
|
||||||
|
|
||||||
|
// find out the video stream id. I have seen files with 01db.
|
||||||
|
for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
|
||||||
|
unsigned char res[2];
|
||||||
|
if (odml_get_vstream_id(idx->ckid, res)) {
|
||||||
|
db = mmioFOURCC(res[0], res[1], 'd', 'b');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// find first non keyframe
|
||||||
|
for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
|
||||||
|
if (!(idx->dwFlags & AVIIF_KEYFRAME) && idx->ckid == db) break;
|
||||||
|
}
|
||||||
|
if (i<priv->idx_size && db) {
|
||||||
|
stream_seek(demuxer->stream, AVI_IDX_OFFSET(idx));
|
||||||
|
id = stream_read_dword_le(demuxer->stream);
|
||||||
|
if (id && id != db) // index fcc and real fcc differ? fix it.
|
||||||
|
for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
|
||||||
|
if (!(idx->dwFlags & AVIIF_KEYFRAME) && idx->ckid == db)
|
||||||
|
idx->ckid = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose>=2) print_index(priv->idx, priv->idx_size);
|
||||||
|
|
||||||
|
demuxer->movi_end=demuxer->stream->end_pos;
|
||||||
|
|
||||||
|
freeout:
|
||||||
|
|
||||||
|
// free unneeded stuff
|
||||||
|
cx = &priv->suidx[0];
|
||||||
|
do {
|
||||||
|
for (j=0;j<cx->nEntriesInUse;j++)
|
||||||
|
if (cx->stdidx[j].nEntriesInUse) free(cx->stdidx[j].aIndex);
|
||||||
|
free(cx->stdidx);
|
||||||
|
|
||||||
|
} while (cx++ != &priv->suidx[priv->suidx_size-1]);
|
||||||
|
free(priv->suidx);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/* Read a saved index file */
|
/* Read a saved index file */
|
||||||
if (index_file_load) {
|
if (index_file_load) {
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
@ -376,6 +635,7 @@ if(index_mode>=2 || (priv->idx_size==0 && index_mode==1)){
|
||||||
idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++];
|
idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++];
|
||||||
idx->ckid=id;
|
idx->ckid=id;
|
||||||
idx->dwFlags=AVIIF_KEYFRAME; // FIXME
|
idx->dwFlags=AVIIF_KEYFRAME; // FIXME
|
||||||
|
idx->dwFlags|=(demuxer->filepos>>16)&0xffff0000U;
|
||||||
idx->dwChunkOffset=(unsigned long)demuxer->filepos;
|
idx->dwChunkOffset=(unsigned long)demuxer->filepos;
|
||||||
idx->dwChunkLength=len;
|
idx->dwChunkLength=len;
|
||||||
|
|
||||||
|
@ -386,8 +646,8 @@ if(index_mode>=2 || (priv->idx_size==0 && index_mode==1)){
|
||||||
if(avi_stream_id(id)==idxfix_videostream){
|
if(avi_stream_id(id)==idxfix_videostream){
|
||||||
switch(idxfix_divx){
|
switch(idxfix_divx){
|
||||||
case 3: c=stream_read_dword(demuxer->stream)<<5; //skip 32+5 bits for m$mpeg4v1
|
case 3: c=stream_read_dword(demuxer->stream)<<5; //skip 32+5 bits for m$mpeg4v1
|
||||||
case 1: if(c&0x40000000) idx->dwFlags=0;break; // divx 3
|
case 1: if(c&0x40000000) idx->dwFlags&=~AVIIF_KEYFRAME;break; // divx 3
|
||||||
case 2: if(c==0x1B6) idx->dwFlags=0;break; // divx 4
|
case 2: if(c==0x1B6) idx->dwFlags&=~AVIIF_KEYFRAME;break; // divx 4
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,89 @@
|
||||||
//#include "config.h" /* get correct definition WORDS_BIGENDIAN */
|
//#include "config.h" /* get correct definition WORDS_BIGENDIAN */
|
||||||
#include "bswap.h"
|
#include "bswap.h"
|
||||||
|
|
||||||
|
typedef struct _avisuperindex_entry {
|
||||||
|
uint64_t qwOffset; // absolute file offset
|
||||||
|
uint32_t dwSize; // size of index chunk at this offset
|
||||||
|
uint32_t dwDuration; // time span in stream ticks
|
||||||
|
} avisuperindex_entry;
|
||||||
|
|
||||||
|
typedef struct _avistdindex_entry {
|
||||||
|
uint32_t dwOffset; // qwBaseOffset + this is absolute file offset
|
||||||
|
uint32_t dwSize; // bit 31 is set if this is NOT a keyframe
|
||||||
|
} avistdindex_entry;
|
||||||
|
|
||||||
|
// Standard index
|
||||||
|
typedef struct _avistdindex_chunk {
|
||||||
|
char fcc[4]; // ix##
|
||||||
|
uint32_t dwSize; // size of this chunk
|
||||||
|
uint16_t wLongsPerEntry; // must be sizeof(aIndex[0])/sizeof(DWORD)
|
||||||
|
uint8_t bIndexSubType; // must be 0
|
||||||
|
uint8_t bIndexType; // must be AVI_INDEX_OF_CHUNKS
|
||||||
|
uint32_t nEntriesInUse; // first unused entry
|
||||||
|
char dwChunkId[4]; // '##dc' or '##db' or '##wb' etc..
|
||||||
|
uint64_t qwBaseOffset; // all dwOffsets in aIndex array are relative to this
|
||||||
|
uint32_t dwReserved3; // must be 0
|
||||||
|
avistdindex_entry *aIndex; // the actual frames
|
||||||
|
} avistdindex_chunk;
|
||||||
|
|
||||||
|
|
||||||
|
// Base Index Form 'indx'
|
||||||
|
typedef struct _avisuperindex_chunk {
|
||||||
|
char fcc[4];
|
||||||
|
uint32_t dwSize; // size of this chunk
|
||||||
|
uint16_t wLongsPerEntry; // size of each entry in aIndex array (must be 4*4 for us)
|
||||||
|
uint8_t bIndexSubType; // future use. must be 0
|
||||||
|
uint8_t bIndexType; // one of AVI_INDEX_* codes
|
||||||
|
uint32_t nEntriesInUse; // index of first unused member in aIndex array
|
||||||
|
char dwChunkId[4]; // fcc of what is indexed
|
||||||
|
uint32_t dwReserved[3]; // meaning differs for each index type/subtype.
|
||||||
|
// 0 if unused
|
||||||
|
avisuperindex_entry *aIndex; // position of ix## chunks
|
||||||
|
avistdindex_chunk *stdidx; // the actual std indices
|
||||||
|
} avisuperindex_chunk;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t CompressedBMHeight;
|
||||||
|
uint32_t CompressedBMWidth;
|
||||||
|
uint32_t ValidBMHeight;
|
||||||
|
uint32_t ValidBMWidth;
|
||||||
|
uint32_t ValidBMXOffset;
|
||||||
|
uint32_t ValidBMYOffset;
|
||||||
|
uint32_t VideoXOffsetInT;
|
||||||
|
uint32_t VideoYValidStartLine;
|
||||||
|
} VIDEO_FIELD_DESC;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t VideoFormatToken;
|
||||||
|
uint32_t VideoStandard;
|
||||||
|
uint32_t dwVerticalRefreshRate;
|
||||||
|
uint32_t dwHTotalInT;
|
||||||
|
uint32_t dwVTotalInLines;
|
||||||
|
uint32_t dwFrameAspectRatio;
|
||||||
|
uint32_t dwFrameWidthInPixels;
|
||||||
|
uint32_t dwFrameHeightInLines;
|
||||||
|
uint32_t nbFieldPerFrame;
|
||||||
|
VIDEO_FIELD_DESC FieldInfo[2];
|
||||||
|
} VideoPropHeader;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FORMAT_UNKNOWN,
|
||||||
|
FORMAT_PAL_SQUARE,
|
||||||
|
FORMAT_PAL_CCIR_601,
|
||||||
|
FORMAT_NTSC_SQUARE,
|
||||||
|
FORMAT_NTSC_CCIR_601,
|
||||||
|
} VIDEO_FORMAT;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
STANDARD_UNKNOWN,
|
||||||
|
STANDARD_PAL,
|
||||||
|
STANDARD_NTSC,
|
||||||
|
STANDARD_SECAM
|
||||||
|
} VIDEO_STANDARD;
|
||||||
|
|
||||||
|
#define MAKE_AVI_ASPECT(a, b) (((a)<<16)|(b))
|
||||||
|
#define GET_AVI_ASPECT(a) ((float)((a)>>16)/(float)((a)&0xffff))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some macros to swap little endian structures read from an AVI file
|
* Some macros to swap little endian structures read from an AVI file
|
||||||
* into machine endian format
|
* into machine endian format
|
||||||
|
@ -72,6 +155,44 @@
|
||||||
(h)->dwChunkOffset = le2me_32((h)->dwChunkOffset); \
|
(h)->dwChunkOffset = le2me_32((h)->dwChunkOffset); \
|
||||||
(h)->dwChunkLength = le2me_32((h)->dwChunkLength); \
|
(h)->dwChunkLength = le2me_32((h)->dwChunkLength); \
|
||||||
}
|
}
|
||||||
|
#define le2me_AVISTDIDXCHUNK(h) {\
|
||||||
|
char c; \
|
||||||
|
c = (h)->fcc[0]; (h)->fcc[0] = (h)->fcc[3]; (h)->fcc[3] = c; \
|
||||||
|
c = (h)->fcc[1]; (h)->fcc[1] = (h)->fcc[2]; (h)->fcc[2] = c; \
|
||||||
|
(h)->dwSize = le2me_32((h)->dwSize); \
|
||||||
|
(h)->wLongsPerEntry = le2me_16((h)->wLongsPerEntry); \
|
||||||
|
(h)->nEntriesInUse = le2me_32((h)->nEntriesInUse); \
|
||||||
|
c = (h)->dwChunkId[0]; (h)->dwChunkId[0] = (h)->dwChunkId[3]; (h)->dwChunkId[3] = c; \
|
||||||
|
c = (h)->dwChunkId[1]; (h)->dwChunkId[1] = (h)->dwChunkId[2]; (h)->dwChunkId[2] = c; \
|
||||||
|
(h)->qwBaseOffset = le2me_64((h)->qwBaseOffset); \
|
||||||
|
(h)->dwReserved3 = le2me_32((h)->dwReserved3); \
|
||||||
|
}
|
||||||
|
#define le2me_AVISTDIDXENTRY(h) {\
|
||||||
|
(h)->dwOffset = le2me_32((h)->dwOffset); \
|
||||||
|
(h)->dwSize = le2me_32((h)->dwSize); \
|
||||||
|
}
|
||||||
|
#define le2me_VideoPropHeader(h) { \
|
||||||
|
(h)->VideoFormatToken = le2me_32((h)->VideoFormatToke) \
|
||||||
|
(h)->VideoStandrad = le2me_32((h)->VideoStandard) \
|
||||||
|
(h)->dwVerticalRefreshRate = le2me_32((h)->dwVerticalRefreshRate) \
|
||||||
|
(h)->dwHTotalInT = le2me_32((h)->dwHTotalInT) \
|
||||||
|
(h)->dwVTotalInLines = le2me_32((h)->dwVTotalInLines) \
|
||||||
|
(h)->dwFrameAspectRatio = le2me_32((h)->dwFrameAspectRatio) \
|
||||||
|
(h)->dwFrameWidthInPixels = le2me_32((h)->dwFrameWidthInPixels) \
|
||||||
|
(h)->dwFrameHeightInLines = le2me_32((h)->dwFrameHeightInLines) \
|
||||||
|
(h)->nbFieldPerFrame = le2me_32((h)->nbFieldPerFrame) \
|
||||||
|
}
|
||||||
|
#define le2me_VIDEO_FIELD_DESC(h) { \
|
||||||
|
(h)->CompressedBMHeight = le2me_32((h)->CompressedBMHeight) \
|
||||||
|
(h)->CompressedBMWidth = le2me_32((h)->CompressedBMWidth) \
|
||||||
|
(h)->ValidBMHeight = le2me_32((h)->ValidBMHeight) \
|
||||||
|
(h)->ValidBMWidth = le2me_32((h)->ValidBMWidth) \
|
||||||
|
(h)->ValidBMXOffset = le2me_32((h)->ValidXOffset) \
|
||||||
|
(h)->ValidBMYOffset = le2me_32((h)->ValidYOffset) \
|
||||||
|
(h)->VideoXOffsetInT = le2me_32((h)->VideoXOffsetInT) \
|
||||||
|
(h)->VideoYValidStartLine = le2me_32((h)->VideoYValidStartLine) \
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define le2me_MainAVIHeader(h) /**/
|
#define le2me_MainAVIHeader(h) /**/
|
||||||
#define le2me_AVIStreamHeader(h) /**/
|
#define le2me_AVIStreamHeader(h) /**/
|
||||||
|
@ -79,12 +200,12 @@
|
||||||
#define le2me_BITMAPINFOHEADER(h) /**/
|
#define le2me_BITMAPINFOHEADER(h) /**/
|
||||||
#define le2me_WAVEFORMATEX(h) /**/
|
#define le2me_WAVEFORMATEX(h) /**/
|
||||||
#define le2me_AVIINDEXENTRY(h) /**/
|
#define le2me_AVIINDEXENTRY(h) /**/
|
||||||
|
#define le2me_AVISTDIDXCHUNK(h) /**/
|
||||||
|
#define le2me_AVISTDIDXENTRY(h) /**/
|
||||||
|
#define le2me_VideoPropHeader(h) /**/
|
||||||
|
#define le2me_VIDEO_FIELD_DESC(h) /**/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// index stuff:
|
// index stuff:
|
||||||
void* idx;
|
void* idx;
|
||||||
|
@ -107,6 +228,13 @@ typedef struct {
|
||||||
unsigned char pts_corrected;
|
unsigned char pts_corrected;
|
||||||
unsigned char pts_has_video;
|
unsigned char pts_has_video;
|
||||||
unsigned int numberofframes;
|
unsigned int numberofframes;
|
||||||
|
avisuperindex_chunk *suidx;
|
||||||
|
int suidx_size;
|
||||||
|
int isodml;
|
||||||
} avi_priv_t;
|
} avi_priv_t;
|
||||||
|
|
||||||
#define AVI_PRIV ((avi_priv_t*)(demuxer->priv))
|
#define AVI_PRIV ((avi_priv_t*)(demuxer->priv))
|
||||||
|
|
||||||
|
#define AVI_IDX_OFFSET(x) ((((uint64_t)(x)->dwFlags&0xffff0000)<<16)+(x)->dwChunkOffset)
|
||||||
|
|
||||||
|
#endif /* _aviheader_h */
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "wine/avifmt.h"
|
#include "wine/avifmt.h"
|
||||||
#include "wine/vfw.h"
|
#include "wine/vfw.h"
|
||||||
|
|
||||||
|
#include "aviheader.h"
|
||||||
|
|
||||||
//#include "codec-cfg.h"
|
//#include "codec-cfg.h"
|
||||||
//#include "stheader.h"
|
//#include "stheader.h"
|
||||||
|
|
||||||
|
@ -105,6 +107,31 @@ void print_video_header(BITMAPINFOHEADER *h){
|
||||||
printf("===========================\n");
|
printf("===========================\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_vprp(VideoPropHeader *vprp){
|
||||||
|
int i;
|
||||||
|
printf("======= Video Properties Header =======\n");
|
||||||
|
printf("Format: %d VideoStandard: %d\n",
|
||||||
|
vprp->VideoFormatToken,vprp->VideoStandard);
|
||||||
|
printf("VRefresh: %d HTotal: %d VTotal: %d\n",
|
||||||
|
vprp->dwVerticalRefreshRate, vprp->dwHTotalInT, vprp->dwVTotalInLines);
|
||||||
|
printf("FrameAspect: %d:%d Framewidth: %d Frameheight: %d\n",
|
||||||
|
vprp->dwFrameAspectRatio >> 16, vprp->dwFrameAspectRatio & 0xffff,
|
||||||
|
vprp->dwFrameWidthInPixels, vprp->dwFrameHeightInLines);
|
||||||
|
printf("Fields: %d\n", vprp->nbFieldPerFrame);
|
||||||
|
for (i=0; i<vprp->nbFieldPerFrame; i++) {
|
||||||
|
VIDEO_FIELD_DESC *vfd = &vprp->FieldInfo[i];
|
||||||
|
printf(" == Field %d description ==\n", i);
|
||||||
|
printf(" CompressedBMHeight: %d CompressedBMWidth: %d\n",
|
||||||
|
vfd->CompressedBMHeight, vfd->CompressedBMWidth);
|
||||||
|
printf(" ValidBMHeight: %d ValidBMWidth: %d\n",
|
||||||
|
vfd->ValidBMHeight, vfd->ValidBMWidth);
|
||||||
|
printf(" ValidBMXOffset: %d ValidBMYOffset: %d\n",
|
||||||
|
vfd->ValidBMXOffset, vfd->ValidBMYOffset);
|
||||||
|
printf(" VideoXOffsetInT: %d VideoYValidStartLine: %d\n",
|
||||||
|
vfd->VideoXOffsetInT, vfd->VideoYValidStartLine);
|
||||||
|
}
|
||||||
|
printf("=======================================\n");
|
||||||
|
}
|
||||||
|
|
||||||
void print_index(AVIINDEXENTRY *idx,int idx_size){
|
void print_index(AVIINDEXENTRY *idx,int idx_size){
|
||||||
int i;
|
int i;
|
||||||
|
@ -114,10 +141,10 @@ void print_index(AVIINDEXENTRY *idx,int idx_size){
|
||||||
for(i=0;i<idx_size;i++){
|
for(i=0;i<idx_size;i++){
|
||||||
int id=avi_stream_id(idx[i].ckid);
|
int id=avi_stream_id(idx[i].ckid);
|
||||||
if(id<0 || id>255) id=255;
|
if(id<0 || id>255) id=255;
|
||||||
printf("%5d: %.4s %4X %08X len:%6ld pos:%7d->%7.3f %7d->%7.3f\n",i,
|
printf("%5d: %.4s %4X %016llX len:%6ld pos:%7d->%7.3f %7d->%7.3f\n",i,
|
||||||
(char *)&idx[i].ckid,
|
(char *)&idx[i].ckid,
|
||||||
(unsigned int)idx[i].dwFlags,
|
(unsigned int)idx[i].dwFlags&0xffff,
|
||||||
(unsigned int)idx[i].dwChunkOffset,
|
(uint64_t)AVI_IDX_OFFSET(&idx[i]),
|
||||||
// idx[i].dwChunkOffset+demuxer->movi_start,
|
// idx[i].dwChunkOffset+demuxer->movi_start,
|
||||||
idx[i].dwChunkLength,
|
idx[i].dwChunkLength,
|
||||||
pos[id],(float)pos[id]/18747.0f,
|
pos[id],(float)pos[id]/18747.0f,
|
||||||
|
@ -128,4 +155,21 @@ void print_index(AVIINDEXENTRY *idx,int idx_size){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_avistdindex_chunk(avistdindex_chunk *h){
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, "====== AVI Standard Index Header ========\n");
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, " FCC (%.4s) dwSize (%d) wLongsPerEntry(%d)\n", h->fcc, h->dwSize, h->wLongsPerEntry);
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, " bIndexSubType (%d) bIndexType (%d)\n", h->bIndexSubType, h->bIndexType);
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, " nEntriesInUse (%d) dwChunkId (%.4s)\n", h->nEntriesInUse, h->dwChunkId);
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, " qwBaseOffset (0x%llX) dwReserved3 (%d)\n", h->qwBaseOffset, h->dwReserved3);
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, "===========================\n");
|
||||||
|
}
|
||||||
|
void print_avisuperindex_chunk(avisuperindex_chunk *h){
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, "====== AVI Super Index Header ========\n");
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, " FCC (%.4s) dwSize (%d) wLongsPerEntry(%d)\n", h->fcc, h->dwSize, h->wLongsPerEntry);
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, " bIndexSubType (%d) bIndexType (%d)\n", h->bIndexSubType, h->bIndexType);
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, " nEntriesInUse (%d) dwChunkId (%.4s)\n", h->nEntriesInUse, h->dwChunkId);
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, " dwReserved[0] (%d) dwReserved[1] (%d) dwReserved[2] (%d)\n",
|
||||||
|
h->dwReserved[0], h->dwReserved[1], h->dwReserved[2]);
|
||||||
|
mp_msg (MSGT_HEADER, MSGL_V, "===========================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -213,7 +213,7 @@ do{
|
||||||
continue; // skip this chunk
|
continue; // skip this chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = priv->idx_offset + (unsigned long)idx->dwChunkOffset;
|
pos = (off_t)priv->idx_offset+AVI_IDX_OFFSET(idx);
|
||||||
if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start) && (demux->stream->flags & STREAM_SEEK)){
|
if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start) && (demux->stream->flags & STREAM_SEEK)){
|
||||||
mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! idx=0x%X \n",pos);
|
mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! idx=0x%X \n",pos);
|
||||||
continue;
|
continue;
|
||||||
|
@ -325,7 +325,7 @@ do{
|
||||||
continue; // skip this chunk
|
continue; // skip this chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = priv->idx_offset+(unsigned long)idx->dwChunkOffset;
|
pos = priv->idx_offset+AVI_IDX_OFFSET(idx);
|
||||||
if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start)){
|
if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start)){
|
||||||
mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! current=0x%X idx=0x%X \n",demux->filepos,pos);
|
mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range! current=0x%X idx=0x%X \n",demux->filepos,pos);
|
||||||
continue;
|
continue;
|
||||||
|
@ -446,6 +446,10 @@ demuxer_t* demux_open_avi(demuxer_t* demuxer){
|
||||||
priv->video_pack_no=0;
|
priv->video_pack_no=0;
|
||||||
priv->audio_block_no=0;
|
priv->audio_block_no=0;
|
||||||
priv->audio_block_size=0;
|
priv->audio_block_size=0;
|
||||||
|
priv->isodml = 0;
|
||||||
|
priv->suidx_size = 0;
|
||||||
|
priv->suidx = NULL;
|
||||||
|
|
||||||
demuxer->priv=(void*)priv;
|
demuxer->priv=(void*)priv;
|
||||||
|
|
||||||
//---- AVI header:
|
//---- AVI header:
|
||||||
|
@ -468,13 +472,13 @@ demuxer_t* demux_open_avi(demuxer_t* demuxer){
|
||||||
if(priv->idx_size>1){
|
if(priv->idx_size>1){
|
||||||
// decide index format:
|
// decide index format:
|
||||||
#if 1
|
#if 1
|
||||||
if((unsigned long)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start ||
|
if((AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[0])<demuxer->movi_start ||
|
||||||
(unsigned long)((AVIINDEXENTRY *)priv->idx)[1].dwChunkOffset<demuxer->movi_start)
|
AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[1])<demuxer->movi_start )&& !priv->isodml)
|
||||||
priv->idx_offset=demuxer->movi_start-4;
|
priv->idx_offset=demuxer->movi_start-4;
|
||||||
else
|
else
|
||||||
priv->idx_offset=0;
|
priv->idx_offset=0;
|
||||||
#else
|
#else
|
||||||
if((unsigned long)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start)
|
if(AVI_IDX_OFFSET(&((AVIINDEXENTRY *)priv->idx)[0])<demuxer->movi_start)
|
||||||
priv->idx_offset=demuxer->movi_start-4;
|
priv->idx_offset=demuxer->movi_start-4;
|
||||||
else
|
else
|
||||||
priv->idx_offset=0;
|
priv->idx_offset=0;
|
||||||
|
@ -494,7 +498,7 @@ demuxer_t* demux_open_avi(demuxer_t* demuxer){
|
||||||
for(i=0;i<priv->idx_size;i++){
|
for(i=0;i<priv->idx_size;i++){
|
||||||
AVIINDEXENTRY* idx=&((AVIINDEXENTRY *)priv->idx)[i];
|
AVIINDEXENTRY* idx=&((AVIINDEXENTRY *)priv->idx)[i];
|
||||||
demux_stream_t* ds=demux_avi_select_stream(demuxer,idx->ckid);
|
demux_stream_t* ds=demux_avi_select_stream(demuxer,idx->ckid);
|
||||||
off_t pos = priv->idx_offset + (unsigned long)idx->dwChunkOffset;
|
off_t pos = priv->idx_offset + AVI_IDX_OFFSET(idx);
|
||||||
if(a_pos==-1 && ds==demuxer->audio){
|
if(a_pos==-1 && ds==demuxer->audio){
|
||||||
a_pos=pos;
|
a_pos=pos;
|
||||||
if(v_pos!=-1) break;
|
if(v_pos!=-1) break;
|
||||||
|
|
|
@ -48,9 +48,9 @@ typedef struct {
|
||||||
typedef struct muxer_t{
|
typedef struct muxer_t{
|
||||||
// encoding:
|
// encoding:
|
||||||
MainAVIHeader avih;
|
MainAVIHeader avih;
|
||||||
unsigned int movi_start;
|
off_t movi_start;
|
||||||
unsigned int movi_end;
|
off_t movi_end;
|
||||||
unsigned int file_end; // for MPEG it's system timestamp in 1/90000 s
|
off_t file_end; // for MPEG it's system timestamp in 1/90000 s
|
||||||
// index:
|
// index:
|
||||||
AVIINDEXENTRY *idx;
|
AVIINDEXENTRY *idx;
|
||||||
int idx_pos;
|
int idx_pos;
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "../version.h"
|
#include "../version.h"
|
||||||
|
|
||||||
//#include "stream.h"
|
#include "stream.h"
|
||||||
//#include "demuxer.h"
|
#include "demuxer.h"
|
||||||
//#include "stheader.h"
|
#include "stheader.h"
|
||||||
|
|
||||||
#include "wine/mmreg.h"
|
#include "wine/mmreg.h"
|
||||||
#include "wine/avifmt.h"
|
#include "wine/avifmt.h"
|
||||||
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "muxer.h"
|
#include "muxer.h"
|
||||||
#include "aviheader.h"
|
#include "aviheader.h"
|
||||||
|
#include "mp_msg.h"
|
||||||
|
|
||||||
extern char *info_name;
|
extern char *info_name;
|
||||||
extern char *info_artist;
|
extern char *info_artist;
|
||||||
|
@ -28,11 +29,38 @@ extern char *info_copyright;
|
||||||
extern char *info_sourceform;
|
extern char *info_sourceform;
|
||||||
extern char *info_comment;
|
extern char *info_comment;
|
||||||
|
|
||||||
|
/* #define ODML_CHUNKLEN 0x02000000 */ /* for testing purposes */
|
||||||
|
#define ODML_CHUNKLEN 0x40000000
|
||||||
|
#define ODML_NOTKEYFRAME 0x80000000U
|
||||||
|
#define MOVIALIGN 0x00001000
|
||||||
|
|
||||||
|
struct avi_odmlidx_entry {
|
||||||
|
uint64_t ofs;
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct avi_odmlsuperidx_entry {
|
||||||
|
uint64_t ofs;
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t duration;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct avi_stream_info {
|
||||||
|
int idxsize;
|
||||||
|
int idxpos;
|
||||||
|
int superidxpos;
|
||||||
|
int superidxsize;
|
||||||
|
struct avi_odmlidx_entry *idx;
|
||||||
|
struct avi_odmlsuperidx_entry *superidx;
|
||||||
|
};
|
||||||
|
|
||||||
static muxer_stream_t* avifile_new_stream(muxer_t *muxer,int type){
|
static muxer_stream_t* avifile_new_stream(muxer_t *muxer,int type){
|
||||||
|
struct avi_stream_info *si;
|
||||||
muxer_stream_t* s;
|
muxer_stream_t* s;
|
||||||
if (!muxer) return NULL;
|
if (!muxer) return NULL;
|
||||||
if(muxer->avih.dwStreams>=MUXER_MAX_STREAMS){
|
if(muxer->avih.dwStreams>=MUXER_MAX_STREAMS){
|
||||||
printf("Too many streams! increase MUXER_MAX_STREAMS !\n");
|
mp_msg(MSGT_MUXER, MSGL_ERR, "Too many streams! increase MUXER_MAX_STREAMS !\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
s=malloc(sizeof(muxer_stream_t));
|
s=malloc(sizeof(muxer_stream_t));
|
||||||
|
@ -44,6 +72,11 @@ static muxer_stream_t* avifile_new_stream(muxer_t *muxer,int type){
|
||||||
s->timer=0.0;
|
s->timer=0.0;
|
||||||
s->size=0;
|
s->size=0;
|
||||||
s->muxer=muxer;
|
s->muxer=muxer;
|
||||||
|
s->priv=si=malloc(sizeof(struct avi_stream_info));
|
||||||
|
memset(si,0,sizeof(struct avi_stream_info));
|
||||||
|
si->idxsize=256;
|
||||||
|
si->idx=malloc(sizeof(struct avi_odmlidx_entry)*si->idxsize);
|
||||||
|
|
||||||
switch(type){
|
switch(type){
|
||||||
case MUXER_TYPE_VIDEO:
|
case MUXER_TYPE_VIDEO:
|
||||||
s->ckid=mmioFOURCC(('0'+s->id/10),('0'+(s->id%10)),'d','c');
|
s->ckid=mmioFOURCC(('0'+s->id/10),('0'+(s->id%10)),'d','c');
|
||||||
|
@ -55,7 +88,7 @@ static muxer_stream_t* avifile_new_stream(muxer_t *muxer,int type){
|
||||||
s->h.fccType=streamtypeAUDIO;
|
s->h.fccType=streamtypeAUDIO;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("WarninG! unknown stream type: %d\n",type);
|
mp_msg(MSGT_MUXER, MSGL_WARN, "Warning! unknown stream type: %d\n",type);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
muxer->avih.dwStreams++;
|
muxer->avih.dwStreams++;
|
||||||
|
@ -90,28 +123,80 @@ if(len>0){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void avifile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags){
|
static void write_avi_list(FILE *f,unsigned int id,int len);
|
||||||
muxer_t *muxer=s->muxer;
|
static void avifile_write_index(muxer_t *muxer);
|
||||||
|
|
||||||
// add to the index:
|
static void avifile_odml_new_riff(muxer_t *muxer)
|
||||||
if(muxer->idx_pos>=muxer->idx_size){
|
{
|
||||||
muxer->idx_size+=256; // 4kB
|
FILE *f = muxer->file;
|
||||||
muxer->idx=realloc(muxer->idx,16*muxer->idx_size);
|
uint32_t riff[3];
|
||||||
|
|
||||||
|
/* Pad to ODML_CHUNKLEN */
|
||||||
|
write_avi_chunk(f,ckidAVIPADDING,ODML_CHUNKLEN - (ftello(f)%ODML_CHUNKLEN) - 8,NULL);
|
||||||
|
|
||||||
|
/* RIFF/AVIX chunk */
|
||||||
|
riff[0]=le2me_32(mmioFOURCC('R','I','F','F'));
|
||||||
|
riff[1]=0;
|
||||||
|
riff[2]=le2me_32(mmioFOURCC('A','V','I','X'));
|
||||||
|
fwrite(riff,12,1,f);
|
||||||
|
|
||||||
|
write_avi_list(f,listtypeAVIMOVIE,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avifile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags){
|
||||||
|
off_t pos;
|
||||||
|
struct avi_stream_info *si = s->priv;
|
||||||
|
muxer_t *muxer=s->muxer;
|
||||||
|
int isodml = muxer->file_end > ODML_CHUNKLEN ? 1 : 0;
|
||||||
|
|
||||||
|
if (!isodml) {
|
||||||
|
// add to the traditional index:
|
||||||
|
if(muxer->idx_pos>=muxer->idx_size){
|
||||||
|
muxer->idx_size+=256; // 4kB
|
||||||
|
muxer->idx=realloc(muxer->idx,16*muxer->idx_size);
|
||||||
|
}
|
||||||
|
muxer->idx[muxer->idx_pos].ckid=s->ckid;
|
||||||
|
muxer->idx[muxer->idx_pos].dwFlags=flags; // keyframe?
|
||||||
|
muxer->idx[muxer->idx_pos].dwChunkOffset=ftello(muxer->file)-(muxer->movi_start-4);
|
||||||
|
muxer->idx[muxer->idx_pos].dwChunkLength=len;
|
||||||
|
++muxer->idx_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to odml index
|
||||||
|
if(si->idxpos>=si->idxsize){
|
||||||
|
si->idxsize+=256;
|
||||||
|
si->idx=realloc(si->idx,sizeof(*si->idx)*si->idxsize);
|
||||||
|
}
|
||||||
|
si->idx[si->idxpos].flags=(flags&AVIIF_KEYFRAME)?0:ODML_NOTKEYFRAME;
|
||||||
|
si->idx[si->idxpos].ofs=ftello(muxer->file);
|
||||||
|
si->idx[si->idxpos].len=len;
|
||||||
|
++si->idxpos;
|
||||||
|
|
||||||
|
pos = muxer->file_end;
|
||||||
|
if (pos < ODML_CHUNKLEN &&
|
||||||
|
pos + 16*muxer->idx_pos + len + 8 > ODML_CHUNKLEN) {
|
||||||
|
|
||||||
|
avifile_write_index(muxer);
|
||||||
|
avifile_odml_new_riff(muxer);
|
||||||
|
|
||||||
|
pos = muxer->file_end = ftello(muxer->file);
|
||||||
|
}
|
||||||
|
if (pos % ODML_CHUNKLEN + len + 8 > ODML_CHUNKLEN) {
|
||||||
|
avifile_odml_new_riff(muxer);
|
||||||
|
muxer->file_end = ftello(muxer->file);
|
||||||
}
|
}
|
||||||
muxer->idx[muxer->idx_pos].ckid=s->ckid;
|
|
||||||
muxer->idx[muxer->idx_pos].dwFlags=flags; // keyframe?
|
|
||||||
muxer->idx[muxer->idx_pos].dwChunkOffset=ftell(muxer->file)-(muxer->movi_start-4);
|
|
||||||
muxer->idx[muxer->idx_pos].dwChunkLength=len;
|
|
||||||
++muxer->idx_pos;
|
|
||||||
|
|
||||||
// write out the chunk:
|
// write out the chunk:
|
||||||
write_avi_chunk(muxer->file,s->ckid,len,s->buffer); /* unsigned char */
|
write_avi_chunk(muxer->file,s->ckid,len,s->buffer); /* unsigned char */
|
||||||
|
|
||||||
// alter counters:
|
// alter counters:
|
||||||
|
if (len > s->h.dwSuggestedBufferSize){
|
||||||
|
s->h.dwSuggestedBufferSize = len;
|
||||||
|
}
|
||||||
if(s->h.dwSampleSize){
|
if(s->h.dwSampleSize){
|
||||||
// CBR
|
// CBR
|
||||||
s->h.dwLength+=len/s->h.dwSampleSize;
|
s->h.dwLength+=len/s->h.dwSampleSize;
|
||||||
if(len%s->h.dwSampleSize) printf("Warning! len isn't divisable by samplesize!\n");
|
if(len%s->h.dwSampleSize) mp_msg(MSGT_MUXER, MSGL_WARN, "Warning! len isn't divisable by samplesize!\n");
|
||||||
} else {
|
} else {
|
||||||
// VBR
|
// VBR
|
||||||
s->h.dwLength++;
|
s->h.dwLength++;
|
||||||
|
@ -120,6 +205,7 @@ static void avifile_write_chunk(muxer_stream_t *s,size_t len,unsigned int flags)
|
||||||
s->size+=len;
|
s->size+=len;
|
||||||
if((unsigned int)len>s->h.dwSuggestedBufferSize) s->h.dwSuggestedBufferSize=len;
|
if((unsigned int)len>s->h.dwSuggestedBufferSize) s->h.dwSuggestedBufferSize=len;
|
||||||
|
|
||||||
|
muxer->file_end += len + 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void write_avi_list(FILE *f,unsigned int id,int len){
|
static void write_avi_list(FILE *f,unsigned int id,int len){
|
||||||
|
@ -137,28 +223,79 @@ static void write_avi_list(FILE *f,unsigned int id,int len){
|
||||||
|
|
||||||
#define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(wf)->cbSize)
|
#define WFSIZE(wf) (sizeof(WAVEFORMATEX)+(wf)->cbSize)
|
||||||
|
|
||||||
|
static unsigned int avi_aspect(sh_video_t *sh_video)
|
||||||
|
{
|
||||||
|
float aspect = sh_video->aspect;
|
||||||
|
if (aspect <= 0.0) {
|
||||||
|
aspect = (float)sh_video->disp_w/(float)sh_video->disp_h;
|
||||||
|
}
|
||||||
|
if (aspect >= 3.99/3.0 &&
|
||||||
|
aspect <= 4.01/3.0) return MAKE_AVI_ASPECT(4,3);
|
||||||
|
if (aspect >= 15.99/9.0 &&
|
||||||
|
aspect <= 16.01/9.0) return MAKE_AVI_ASPECT(16,9);
|
||||||
|
if (aspect >= 0.99 &&
|
||||||
|
aspect <= 1.01) return MAKE_AVI_ASPECT(1,1);
|
||||||
|
if (aspect<1.0) return MAKE_AVI_ASPECT((int)(aspect*8192),8192);
|
||||||
|
return MAKE_AVI_ASPECT(8192,(int)(8192/aspect));
|
||||||
|
}
|
||||||
|
|
||||||
static void avifile_write_header(muxer_t *muxer){
|
static void avifile_write_header(muxer_t *muxer){
|
||||||
uint32_t riff[3];
|
uint32_t riff[3];
|
||||||
|
unsigned int dmlh[1];
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int hdrsize;
|
unsigned int hdrsize;
|
||||||
muxer_info_t info[16];
|
muxer_info_t info[16];
|
||||||
FILE *f=muxer->file;
|
FILE *f = muxer->file;
|
||||||
|
VideoPropHeader vprp;
|
||||||
|
off_t pos;
|
||||||
|
int isodml = muxer->file_end > ODML_CHUNKLEN ? 1 : 0;
|
||||||
|
|
||||||
|
if (isodml) {
|
||||||
|
for (pos = 0; pos < muxer->file_end; pos += ODML_CHUNKLEN) {
|
||||||
|
unsigned int rifflen, movilen;
|
||||||
|
|
||||||
|
/* fixup RIFF length */
|
||||||
|
if (muxer->file_end - pos > ODML_CHUNKLEN) {
|
||||||
|
rifflen = le2me_32(ODML_CHUNKLEN - 8);
|
||||||
|
movilen = le2me_32(ODML_CHUNKLEN - 20);
|
||||||
|
} else {
|
||||||
|
rifflen = le2me_32(muxer->file_end - pos - 8);
|
||||||
|
movilen = le2me_32(muxer->file_end - pos - 20);
|
||||||
|
}
|
||||||
|
fseeko(f, pos + 4, SEEK_SET);
|
||||||
|
fwrite(&rifflen,4,1,f);
|
||||||
|
|
||||||
|
/* fixup movi length */
|
||||||
|
if (pos > 0) {
|
||||||
|
fseeko(f, pos + 16, SEEK_SET);
|
||||||
|
fwrite(&movilen,4,1,f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fseeko(f, 12, SEEK_SET);
|
||||||
|
} else {
|
||||||
|
// RIFF header:
|
||||||
|
riff[0]=mmioFOURCC('R','I','F','F');
|
||||||
|
riff[1]=muxer->file_end-2*sizeof(unsigned int); // filesize
|
||||||
|
riff[2]=formtypeAVI; // 'AVI '
|
||||||
|
riff[0]=le2me_32(riff[0]);
|
||||||
|
riff[1]=le2me_32(riff[1]);
|
||||||
|
riff[2]=le2me_32(riff[2]);
|
||||||
|
fwrite(&riff,12,1,f);
|
||||||
|
}
|
||||||
|
|
||||||
// RIFF header:
|
|
||||||
riff[0]=mmioFOURCC('R','I','F','F');
|
|
||||||
riff[1]=muxer->file_end-2*sizeof(unsigned int); // filesize
|
|
||||||
riff[2]=formtypeAVI; // 'AVI '
|
|
||||||
riff[0]=le2me_32(riff[0]);
|
|
||||||
riff[1]=le2me_32(riff[1]);
|
|
||||||
riff[2]=le2me_32(riff[2]);
|
|
||||||
fwrite(&riff,12,1,f);
|
|
||||||
// update AVI header:
|
// update AVI header:
|
||||||
if(muxer->def_v){
|
if(muxer->def_v){
|
||||||
|
int i;
|
||||||
muxer->avih.dwMicroSecPerFrame=1000000.0*muxer->def_v->h.dwScale/muxer->def_v->h.dwRate;
|
muxer->avih.dwMicroSecPerFrame=1000000.0*muxer->def_v->h.dwScale/muxer->def_v->h.dwRate;
|
||||||
// muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME
|
// muxer->avih.dwMaxBytesPerSec=1000000; // dummy!!!!! FIXME
|
||||||
// muxer->avih.dwPaddingGranularity=2; // ???
|
// muxer->avih.dwPaddingGranularity=2; // ???
|
||||||
muxer->avih.dwFlags|=AVIF_ISINTERLEAVED|AVIF_TRUSTCKTYPE;
|
muxer->avih.dwFlags|=AVIF_ISINTERLEAVED|AVIF_TRUSTCKTYPE;
|
||||||
muxer->avih.dwTotalFrames=muxer->def_v->h.dwLength;
|
muxer->avih.dwTotalFrames=0;
|
||||||
|
for (i=0; i<muxer->idx_pos; i++) {
|
||||||
|
if (muxer->idx[i].ckid == muxer->def_v->ckid)
|
||||||
|
muxer->avih.dwTotalFrames++;
|
||||||
|
}
|
||||||
// muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize;
|
// muxer->avih.dwSuggestedBufferSize=muxer->def_v->h.dwSuggestedBufferSize;
|
||||||
muxer->avih.dwWidth=muxer->def_v->bih->biWidth;
|
muxer->avih.dwWidth=muxer->def_v->bih->biWidth;
|
||||||
muxer->avih.dwHeight=muxer->def_v->bih->biHeight;
|
muxer->avih.dwHeight=muxer->def_v->bih->biHeight;
|
||||||
|
@ -166,18 +303,26 @@ static void avifile_write_header(muxer_t *muxer){
|
||||||
|
|
||||||
// AVI header:
|
// AVI header:
|
||||||
hdrsize=sizeof(muxer->avih)+8;
|
hdrsize=sizeof(muxer->avih)+8;
|
||||||
|
if (isodml) hdrsize+=sizeof(dmlh)+20; // dmlh
|
||||||
// calc total header size:
|
// calc total header size:
|
||||||
for(i=0;i<muxer->avih.dwStreams;i++){
|
for(i=0;i<muxer->avih.dwStreams;i++){
|
||||||
|
muxer_stream_t *s = muxer->streams[i];
|
||||||
|
struct avi_stream_info *si = s->priv;
|
||||||
|
|
||||||
hdrsize+=12; // LIST
|
hdrsize+=12; // LIST
|
||||||
hdrsize+=sizeof(muxer->streams[i]->h)+8; // strh
|
hdrsize+=sizeof(muxer->streams[i]->h)+8; // strh
|
||||||
switch(muxer->streams[i]->type){
|
switch(muxer->streams[i]->type){
|
||||||
case MUXER_TYPE_VIDEO:
|
case MUXER_TYPE_VIDEO:
|
||||||
hdrsize+=muxer->streams[i]->bih->biSize+8; // strf
|
hdrsize+=muxer->streams[i]->bih->biSize+8; // strf
|
||||||
|
hdrsize+=8+4*(9+8*1); // vprp
|
||||||
break;
|
break;
|
||||||
case MUXER_TYPE_AUDIO:
|
case MUXER_TYPE_AUDIO:
|
||||||
hdrsize+=WFSIZE(muxer->streams[i]->wf)+8; // strf
|
hdrsize+=WFSIZE(muxer->streams[i]->wf)+8; // strf
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (isodml && si && si->superidx && si->superidxsize) {
|
||||||
|
hdrsize += 32 + 16*si->superidxsize; //indx
|
||||||
|
}
|
||||||
}
|
}
|
||||||
write_avi_list(f,listtypeAVIHEADER,hdrsize);
|
write_avi_list(f,listtypeAVIHEADER,hdrsize);
|
||||||
|
|
||||||
|
@ -187,40 +332,103 @@ static void avifile_write_header(muxer_t *muxer){
|
||||||
|
|
||||||
// stream headers:
|
// stream headers:
|
||||||
for(i=0;i<muxer->avih.dwStreams;i++){
|
for(i=0;i<muxer->avih.dwStreams;i++){
|
||||||
hdrsize=sizeof(muxer->streams[i]->h)+8; // strh
|
muxer_stream_t *s = muxer->streams[i];
|
||||||
switch(muxer->streams[i]->type){
|
struct avi_stream_info *si = s->priv;
|
||||||
|
unsigned int idxhdr[8];
|
||||||
|
int j,n;
|
||||||
|
|
||||||
|
hdrsize=sizeof(s->h)+8; // strh
|
||||||
|
if (si && si->superidx && si->superidxsize) {
|
||||||
|
hdrsize += 32 + 16*si->superidxsize; //indx
|
||||||
|
}
|
||||||
|
switch(s->type){
|
||||||
case MUXER_TYPE_VIDEO:
|
case MUXER_TYPE_VIDEO:
|
||||||
hdrsize+=muxer->streams[i]->bih->biSize+8; // strf
|
hdrsize+=s->bih->biSize+8; // strf
|
||||||
muxer->streams[i]->h.fccHandler = muxer->streams[i]->bih->biCompression;
|
s->h.fccHandler = s->bih->biCompression;
|
||||||
|
s->h.rcFrame.right = s->bih->biWidth;
|
||||||
|
s->h.rcFrame.bottom = s->bih->biHeight;
|
||||||
|
// fill out vprp info
|
||||||
|
memset(&vprp, 0, sizeof(vprp));
|
||||||
|
vprp.dwVerticalRefreshRate = (s->h.dwRate+s->h.dwScale-1)/s->h.dwScale;
|
||||||
|
vprp.dwHTotalInT = muxer->avih.dwWidth;
|
||||||
|
vprp.dwVTotalInLines = muxer->avih.dwHeight;
|
||||||
|
vprp.dwFrameAspectRatio = avi_aspect(s->source);
|
||||||
|
vprp.dwFrameWidthInPixels = muxer->avih.dwWidth;
|
||||||
|
vprp.dwFrameHeightInLines = muxer->avih.dwHeight;
|
||||||
|
vprp.nbFieldPerFrame = 1;
|
||||||
|
vprp.FieldInfo[0].CompressedBMHeight = muxer->avih.dwHeight;
|
||||||
|
vprp.FieldInfo[0].CompressedBMWidth = muxer->avih.dwWidth;
|
||||||
|
vprp.FieldInfo[0].ValidBMHeight = muxer->avih.dwHeight;
|
||||||
|
vprp.FieldInfo[0].ValidBMWidth = muxer->avih.dwWidth;
|
||||||
|
hdrsize+=8+4*(9+8*1); // vprp
|
||||||
break;
|
break;
|
||||||
case MUXER_TYPE_AUDIO:
|
case MUXER_TYPE_AUDIO:
|
||||||
hdrsize+=WFSIZE(muxer->streams[i]->wf)+8; // strf
|
hdrsize+=WFSIZE(s->wf)+8; // strf
|
||||||
muxer->streams[i]->h.fccHandler = muxer->streams[i]->wf->wFormatTag;
|
s->h.fccHandler = s->wf->wFormatTag;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
write_avi_list(f,listtypeSTREAMHEADER,hdrsize);
|
|
||||||
le2me_AVIStreamHeader(&muxer->streams[i]->h);
|
|
||||||
write_avi_chunk(f,ckidSTREAMHEADER,sizeof(muxer->streams[i]->h),&muxer->streams[i]->h); /* AVISTreamHeader */ // strh
|
|
||||||
le2me_AVIStreamHeader(&muxer->streams[i]->h);
|
|
||||||
|
|
||||||
switch(muxer->streams[i]->type){
|
write_avi_list(f,listtypeSTREAMHEADER,hdrsize);
|
||||||
|
le2me_AVIStreamHeader(&s->h);
|
||||||
|
write_avi_chunk(f,ckidSTREAMHEADER,sizeof(s->h),&s->h); /* AVISTreamHeader */ // strh
|
||||||
|
le2me_AVIStreamHeader(&s->h);
|
||||||
|
|
||||||
|
switch(s->type){
|
||||||
case MUXER_TYPE_VIDEO:
|
case MUXER_TYPE_VIDEO:
|
||||||
{
|
{
|
||||||
int biSize=muxer->streams[i]->bih->biSize;
|
int biSize=s->bih->biSize;
|
||||||
le2me_BITMAPINFOHEADER(muxer->streams[i]->bih);
|
le2me_BITMAPINFOHEADER(s->bih);
|
||||||
write_avi_chunk(f,ckidSTREAMFORMAT,biSize,muxer->streams[i]->bih); /* BITMAPINFOHEADER */
|
write_avi_chunk(f,ckidSTREAMFORMAT,biSize,s->bih); /* BITMAPINFOHEADER */
|
||||||
le2me_BITMAPINFOHEADER(muxer->streams[i]->bih);
|
le2me_BITMAPINFOHEADER(s->bih);
|
||||||
|
le2me_VideoPropHeader(&vprp);
|
||||||
|
le2me_VIDEO_FIELD_DESC(&vprp.FieldInfo[0]);
|
||||||
|
le2me_VIDEO_FIELD_DESC(&vprp.FieldInfo[1]);
|
||||||
|
write_avi_chunk(f,mmioFOURCC('v','p','r','p'),
|
||||||
|
sizeof(VideoPropHeader) -
|
||||||
|
sizeof(VIDEO_FIELD_DESC)*(2-vprp.nbFieldPerFrame),
|
||||||
|
&vprp); /* Video Properties Header */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MUXER_TYPE_AUDIO:
|
case MUXER_TYPE_AUDIO:
|
||||||
{
|
{
|
||||||
int wfsize = WFSIZE(muxer->streams[i]->wf);
|
int wfsize = WFSIZE(s->wf);
|
||||||
le2me_WAVEFORMATEX(muxer->streams[i]->wf);
|
le2me_WAVEFORMATEX(s->wf);
|
||||||
write_avi_chunk(f,ckidSTREAMFORMAT,wfsize,muxer->streams[i]->wf); /* WAVEFORMATEX */
|
write_avi_chunk(f,ckidSTREAMFORMAT,wfsize,s->wf); /* WAVEFORMATEX */
|
||||||
le2me_WAVEFORMATEX(muxer->streams[i]->wf);
|
le2me_WAVEFORMATEX(s->wf);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (isodml && si && si->superidx && si->superidxsize) {
|
||||||
|
n = si->superidxsize;
|
||||||
|
|
||||||
|
idxhdr[0] = le2me_32(mmioFOURCC('i', 'n', 'd', 'x'));
|
||||||
|
idxhdr[1] = le2me_32(24 + 16*n);
|
||||||
|
idxhdr[2] = le2me_32(0x00000004);
|
||||||
|
idxhdr[3] = le2me_32(si->superidxpos);
|
||||||
|
idxhdr[4] = le2me_32(s->ckid);
|
||||||
|
idxhdr[5] = 0;
|
||||||
|
idxhdr[6] = 0;
|
||||||
|
idxhdr[7] = 0;
|
||||||
|
|
||||||
|
fwrite(idxhdr,sizeof(idxhdr),1,f);
|
||||||
|
for (j=0; j<n; j++) {
|
||||||
|
struct avi_odmlsuperidx_entry *entry = &si->superidx[j];
|
||||||
|
unsigned int data[4];
|
||||||
|
data[0] = le2me_32(entry->ofs);
|
||||||
|
data[1] = le2me_32(entry->ofs >> 32);
|
||||||
|
data[2] = le2me_32(entry->len);
|
||||||
|
data[3] = le2me_32(entry->duration);
|
||||||
|
fwrite(data,sizeof(data),1,f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ODML
|
||||||
|
if (isodml) {
|
||||||
|
memset(dmlh, 0, sizeof(dmlh));
|
||||||
|
dmlh[0] = le2me_32(muxer->avih.dwTotalFrames);
|
||||||
|
write_avi_list(f,mmioFOURCC('o','d','m','l'),sizeof(dmlh)+8);
|
||||||
|
write_avi_chunk(f,mmioFOURCC('d','m','l','h'),sizeof(dmlh),dmlh);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============= INFO ===============
|
// ============= INFO ===============
|
||||||
|
@ -274,14 +482,115 @@ info[i].id=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// JUNK:
|
// JUNK:
|
||||||
write_avi_chunk(f,ckidAVIPADDING,2048-(ftell(f)&2047)-8,NULL); /* junk */
|
write_avi_chunk(f,ckidAVIPADDING,MOVIALIGN-(ftello(f)%MOVIALIGN)-8,NULL); /* junk */
|
||||||
// 'movi' header:
|
if (!isodml) {
|
||||||
write_avi_list(f,listtypeAVIMOVIE,muxer->movi_end-ftell(f)-12);
|
// 'movi' header:
|
||||||
muxer->movi_start=ftell(f);
|
write_avi_list(f,listtypeAVIMOVIE,muxer->movi_end-ftello(f)-12);
|
||||||
|
} else {
|
||||||
|
if (ftello(f) != MOVIALIGN) {
|
||||||
|
mp_msg(MSGT_MUXER, MSGL_ERR, "Opendml superindex is too big for reserved space!\n");
|
||||||
|
mp_msg(MSGT_MUXER, MSGL_ERR, "Expected filepos %d, real filepos %d, missing space %d\n", MOVIALIGN, ftell(muxer->file), ftell(muxer->file)-MOVIALIGN);
|
||||||
|
mp_msg(MSGT_MUXER, MSGL_ERR, "Try increasing MOVIALIGN in libmpdemux/muxer_avi.c\n", MOVIALIGN, ftell(muxer->file), ftell(muxer->file)-MOVIALIGN);
|
||||||
|
}
|
||||||
|
write_avi_list(f,listtypeAVIMOVIE,muxer->movi_end-ftello(f)-12);
|
||||||
|
}
|
||||||
|
muxer->movi_start=ftello(muxer->file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void avifile_odml_write_index(muxer_t *muxer){
|
||||||
|
muxer_stream_t* s;
|
||||||
|
struct avi_stream_info *si;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i=0; i<muxer->avih.dwStreams; i++) {
|
||||||
|
int j,k,n,idxpos,len,last,entries_per_subidx;
|
||||||
|
unsigned int idxhdr[8];
|
||||||
|
s = muxer->streams[i];
|
||||||
|
si = s->priv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* According to Avery Lee MSMP wants the subidx chunks to have the same size.
|
||||||
|
*
|
||||||
|
* So this code figures out how many entries we can put into
|
||||||
|
* an ix?? chunk, so that each ix?? chunk has the same size and the offsets
|
||||||
|
* don't overflow (Using ODML_CHUNKLEN for that is a bit more restrictive
|
||||||
|
* than it has to be though).
|
||||||
|
*/
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
n = 0;
|
||||||
|
entries_per_subidx = INT_MAX;
|
||||||
|
do {
|
||||||
|
off_t start = si->idx[0].ofs;
|
||||||
|
last = entries_per_subidx;
|
||||||
|
for (j=0; j<si->idxpos; j++) {
|
||||||
|
len = si->idx[j].ofs - start;
|
||||||
|
if(len >= ODML_CHUNKLEN || n >= entries_per_subidx) {
|
||||||
|
if (entries_per_subidx > n) {
|
||||||
|
entries_per_subidx = n;
|
||||||
|
}
|
||||||
|
start = si->idx[j].ofs;
|
||||||
|
len = 0;
|
||||||
|
n = 0;
|
||||||
|
}
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
} while (last != entries_per_subidx);
|
||||||
|
|
||||||
|
si->superidxpos = (si->idxpos+entries_per_subidx-1) / entries_per_subidx;
|
||||||
|
|
||||||
|
mp_msg(MSGT_MUXER, MSGL_V, "ODML: Stream %d: Using %d entries per subidx, %d entries in superidx\n",
|
||||||
|
i, entries_per_subidx, si->superidxpos);
|
||||||
|
|
||||||
|
si->superidxsize = si->superidxpos;
|
||||||
|
si->superidx = malloc(sizeof(*si->superidx) * si->superidxsize);
|
||||||
|
memset(si->superidx, 0, sizeof(*si->superidx) * si->superidxsize);
|
||||||
|
|
||||||
|
idxpos = 0;
|
||||||
|
for (j=0; j<si->superidxpos; j++) {
|
||||||
|
off_t start = si->idx[idxpos].ofs;
|
||||||
|
int duration;
|
||||||
|
|
||||||
|
duration = 0;
|
||||||
|
for (k=0; k<entries_per_subidx && idxpos+k<si->idxpos; k++) {
|
||||||
|
duration += s->h.dwSampleSize ? si->idx[idxpos+k].len/s->h.dwSampleSize : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
idxhdr[0] = le2me_32((s->ckid << 16) | mmioFOURCC('i', 'x', 0, 0));
|
||||||
|
idxhdr[1] = le2me_32(24 + 8*k);
|
||||||
|
idxhdr[2] = le2me_32(0x01000002);
|
||||||
|
idxhdr[3] = le2me_32(k);
|
||||||
|
idxhdr[4] = le2me_32(s->ckid);
|
||||||
|
idxhdr[5] = le2me_32(start + 8);
|
||||||
|
idxhdr[6] = le2me_32((start + 8)>> 32);
|
||||||
|
idxhdr[7] = 0; /* unused */
|
||||||
|
|
||||||
|
si->superidx[j].len = 32 + 8*k;
|
||||||
|
si->superidx[j].ofs = ftello(muxer->file);
|
||||||
|
si->superidx[j].duration = duration;
|
||||||
|
|
||||||
|
fwrite(idxhdr,sizeof(idxhdr),1,muxer->file);
|
||||||
|
for (k=0; k<entries_per_subidx && idxpos<si->idxpos; k++) {
|
||||||
|
unsigned int entry[2];
|
||||||
|
entry[0] = le2me_32(si->idx[idxpos].ofs - start);
|
||||||
|
entry[1] = le2me_32(si->idx[idxpos].len | si->idx[idxpos].flags);
|
||||||
|
idxpos++;
|
||||||
|
fwrite(entry,sizeof(entry),1,muxer->file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
muxer->file_end=ftello(muxer->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void avifile_write_index(muxer_t *muxer){
|
static void avifile_write_index(muxer_t *muxer){
|
||||||
muxer->movi_end=ftell(muxer->file);
|
|
||||||
|
if(muxer->file_end > ODML_CHUNKLEN &&
|
||||||
|
muxer->idx && muxer->idx_pos>0) {
|
||||||
|
avifile_odml_write_index(muxer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
muxer->movi_end=ftello(muxer->file);
|
||||||
if(muxer->idx && muxer->idx_pos>0){
|
if(muxer->idx && muxer->idx_pos>0){
|
||||||
int i;
|
int i;
|
||||||
// fixup index entries:
|
// fixup index entries:
|
||||||
|
@ -292,7 +601,7 @@ static void avifile_write_index(muxer_t *muxer){
|
||||||
for (i=0; i<muxer->idx_pos; i++) le2me_AVIINDEXENTRY((&muxer->idx[i]));
|
for (i=0; i<muxer->idx_pos; i++) le2me_AVIINDEXENTRY((&muxer->idx[i]));
|
||||||
muxer->avih.dwFlags|=AVIF_HASINDEX;
|
muxer->avih.dwFlags|=AVIF_HASINDEX;
|
||||||
}
|
}
|
||||||
muxer->file_end=ftell(muxer->file);
|
muxer->file_end=ftello(muxer->file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void muxer_init_muxer_avi(muxer_t *muxer){
|
void muxer_init_muxer_avi(muxer_t *muxer){
|
||||||
|
|
|
@ -663,6 +663,12 @@ case VCODEC_COPY:
|
||||||
mux_v->bih->biBitCount=24; // FIXME!!!
|
mux_v->bih->biBitCount=24; // FIXME!!!
|
||||||
mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8);
|
mux_v->bih->biSizeImage=mux_v->bih->biWidth*mux_v->bih->biHeight*(mux_v->bih->biBitCount/8);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* FIXME: with -ovc copy we don't get aspect ratio information
|
||||||
|
* from the source stream.
|
||||||
|
*/
|
||||||
|
if(movie_aspect>-1.0) sh_video->aspect = movie_aspect;
|
||||||
|
|
||||||
printf("videocodec: framecopy (%dx%d %dbpp fourcc=%x)\n",
|
printf("videocodec: framecopy (%dx%d %dbpp fourcc=%x)\n",
|
||||||
mux_v->bih->biWidth, mux_v->bih->biHeight,
|
mux_v->bih->biWidth, mux_v->bih->biHeight,
|
||||||
mux_v->bih->biBitCount, mux_v->bih->biCompression);
|
mux_v->bih->biBitCount, mux_v->bih->biCompression);
|
||||||
|
|
Loading…
Reference in New Issue