libmpeg3-1.5.4/0000755000175000017500000000000010026623430013433 5ustar enderender00000000000000libmpeg3-1.5.4/audio/0000755000175000017500000000000010012353221014525 5ustar enderender00000000000000libmpeg3-1.5.4/audio/Makefile0000644000175000017500000000045307742725645016224 0ustar enderender00000000000000include ../global_config export CFLAGS OBJS = \ ac3.o \ bit_allocation.o \ dct.o \ exponents.o \ header.o \ layer2.o \ layer3.o \ mantissa.o \ mpeg3audio.o \ pcm.o \ synthesizers.o \ tables.o all: $(OBJS) .c.o: $(CC) -c `./c_flags` $*.c .s.o: $(CC) -f elf $*.s clean: rm -f *.o libmpeg3-1.5.4/audio/ac3.c0000644000175000017500000000531110003145216015342 0ustar enderender00000000000000#include #include #include "a52.h" #include "mpeg3private.h" #include "mpeg3protos.h" #include mpeg3_ac3_t* mpeg3_new_ac3() { mpeg3_ac3_t *result = calloc(1, sizeof(mpeg3_ac3_t)); result->stream = mpeg3bits_new_stream(0, 0); result->state = a52_init(0); result->output = a52_samples(result->state); return result; } void mpeg3_delete_ac3(mpeg3_ac3_t *audio) { mpeg3bits_delete_stream(audio->stream); a52_free(audio->state); free(audio); } /* Return 1 if it isn't an AC3 header */ int mpeg3_ac3_check(unsigned char *header) { int flags, samplerate, bitrate; return !a52_syncinfo(header, &flags, &samplerate, &bitrate); } /* Decode AC3 header */ int mpeg3_ac3_header(mpeg3_ac3_t *audio, unsigned char *header) { int result = 0; audio->flags = 0; //printf("mpeg3_ac3_header %02x%02x%02x%02x%02x%02x%02x%02x\n", header[0], header[1], header[2], header[3], header[4], header[5], header[6], header[7]); result = a52_syncinfo(header, &audio->flags, &audio->samplerate, &audio->bitrate); if(result) { audio->framesize = result; audio->channels = 0; if(audio->flags & A52_LFE) audio->channels++; //printf("mpeg3_ac3_header %02x\n", audio->flags & A52_CHANNEL_MASK); switch(audio->flags & A52_CHANNEL_MASK) { case A52_CHANNEL: audio->channels++; break; case A52_MONO: audio->channels++; break; case A52_STEREO: audio->channels += 2; break; case A52_3F: audio->channels += 3; break; case A52_2F1R: audio->channels += 3; break; case A52_3F1R: audio->channels += 4; break; case A52_2F2R: audio->channels += 4; break; case A52_3F2R: audio->channels += 5; break; case A52_DOLBY: audio->channels += 2; break; default: printf("mpeg3_ac3_header: unknown channel code: %p\n", audio->flags & A52_CHANNEL_MASK); break; } } //printf("mpeg3_ac3_header 1 %d\n", audio->channels); return result; } int mpeg3audio_doac3(mpeg3_ac3_t *audio, char *frame, int frame_size, float **output, int render) { int output_position = 0; sample_t level = 1; int i, j, k, l; //printf("mpeg3audio_doac3 1\n"); a52_frame(audio->state, frame, &audio->flags, &level, 0); //printf("mpeg3audio_doac3 2\n"); a52_dynrng(audio->state, NULL, NULL); //printf("mpeg3audio_doac3 3\n"); for(i = 0; i < 6; i++) { if(!a52_block(audio->state)) { l = 0; if(render) { for(j = 0; j < audio->channels; j++) { for(k = 0; k < 256; k++) { output[j][output_position + k] = ((sample_t*)audio->output)[l]; l++; } } } output_position += 256; } } //printf("mpeg3audio_doac3 4 %d\n", output_position); return output_position; } libmpeg3-1.5.4/audio/ac3.h0000644000175000017500000000004407742725645015377 0ustar enderender00000000000000#ifndef AC3_H #define AC3_H #endif libmpeg3-1.5.4/audio/bit_allocation.c0000644000175000017500000004062207742725645017715 0ustar enderender00000000000000/* * * Copyright (C) Aaron Holtzman - May 1999 * * * This file is part of libmpeg3 * * libmpeg3 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * libmpeg3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "mpeg3audio.h" #include /* Bit allocation tables */ static short mpeg3_slowdec[] = { 0x0f, 0x11, 0x13, 0x15 }; static short mpeg3_fastdec[] = { 0x3f, 0x53, 0x67, 0x7b }; static short mpeg3_slowgain[] = { 0x540, 0x4d8, 0x478, 0x410 }; static short mpeg3_dbpbtab[] = { 0x000, 0x700, 0x900, 0xb00 }; static unsigned short mpeg3_floortab[] = { 0x2f0, 0x2b0, 0x270, 0x230, 0x1f0, 0x170, 0x0f0, 0xf800 }; static short mpeg3_fastgain[] = { 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400 }; static short mpeg3_bndtab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, 34, 37, 40, 43, 46, 49, 55, 61, 67, 73, 79, 85, 97, 109, 121, 133, 157, 181, 205, 229 }; static short mpeg3_bndsz[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 24, 24, 24, 24, 24 }; static short mpeg3_masktab[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 28, 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 34, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 0, 0, 0 }; static short mpeg3_latab[] = { 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003b, 0x003a, 0x0039, 0x0038, 0x0037, 0x0036, 0x0035, 0x0034, 0x0034, 0x0033, 0x0032, 0x0031, 0x0030, 0x002f, 0x002f, 0x002e, 0x002d, 0x002c, 0x002c, 0x002b, 0x002a, 0x0029, 0x0029, 0x0028, 0x0027, 0x0026, 0x0026, 0x0025, 0x0024, 0x0024, 0x0023, 0x0023, 0x0022, 0x0021, 0x0021, 0x0020, 0x0020, 0x001f, 0x001e, 0x001e, 0x001d, 0x001d, 0x001c, 0x001c, 0x001b, 0x001b, 0x001a, 0x001a, 0x0019, 0x0019, 0x0018, 0x0018, 0x0017, 0x0017, 0x0016, 0x0016, 0x0015, 0x0015, 0x0015, 0x0014, 0x0014, 0x0013, 0x0013, 0x0013, 0x0012, 0x0012, 0x0012, 0x0011, 0x0011, 0x0011, 0x0010, 0x0010, 0x0010, 0x000f, 0x000f, 0x000f, 0x000e, 0x000e, 0x000e, 0x000d, 0x000d, 0x000d, 0x000d, 0x000c, 0x000c, 0x000c, 0x000c, 0x000b, 0x000b, 0x000b, 0x000b, 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0009, 0x0009, 0x0009, 0x0009, 0x0009, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }; static short mpeg3_hth[][50] = { { 0x04d0, 0x04d0, 0x0440, 0x0400, 0x03e0, 0x03c0, 0x03b0, 0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390, 0x0380, 0x0380, 0x0370, 0x0370, 0x0360, 0x0360, 0x0350, 0x0350, 0x0340, 0x0340, 0x0330, 0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0, 0x02f0, 0x02f0, 0x0300, 0x0310, 0x0340, 0x0390, 0x03e0, 0x0420, 0x0460, 0x0490, 0x04a0, 0x0460, 0x0440, 0x0440, 0x0520, 0x0800, 0x0840, 0x0840 }, { 0x04f0, 0x04f0, 0x0460, 0x0410, 0x03e0, 0x03d0, 0x03c0, 0x03b0, 0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390, 0x0380, 0x0380, 0x0380, 0x0370, 0x0370, 0x0360, 0x0360, 0x0350, 0x0350, 0x0340, 0x0340, 0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0, 0x02f0, 0x02f0, 0x0300, 0x0320, 0x0350, 0x0390, 0x03e0, 0x0420, 0x0450, 0x04a0, 0x0490, 0x0460, 0x0440, 0x0480, 0x0630, 0x0840, 0x0840 }, { 0x0580, 0x0580, 0x04b0, 0x0450, 0x0420, 0x03f0, 0x03e0, 0x03d0, 0x03c0, 0x03b0, 0x03b0, 0x03b0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x03a0, 0x0390, 0x0390, 0x0390, 0x0390, 0x0380, 0x0380, 0x0380, 0x0370, 0x0360, 0x0350, 0x0340, 0x0330, 0x0320, 0x0310, 0x0300, 0x02f0, 0x02f0, 0x02f0, 0x0300, 0x0310, 0x0330, 0x0350, 0x03c0, 0x0410, 0x0470, 0x04a0, 0x0460, 0x0440, 0x0450, 0x04e0 } }; static short mpeg3_baptab[] = { 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; static int logadd(int a, int b) { int c; int address; c = a - b; address = mpeg3_min((abs(c) >> 1), 255); if(c >= 0) return(a + mpeg3_latab[address]); else return(b + mpeg3_latab[address]); } int mpeg3audio_ac3_calc_lowcomp(int a, int b0, int b1, int bin) { if(bin < 7) { if((b0 + 256) == b1) a = 384; else if(b0 > b1) a = mpeg3_max(0, a - 64); } else if(bin < 20) { if((b0 + 256) == b1) a = 320; else if(b0 > b1) a = mpeg3_max(0, a - 64) ; } else a = mpeg3_max(0, a - 128); return(a); } void mpeg3audio_ac3_ba_compute_psd(int start, int end, short exps[], short psd[], short bndpsd[]) { int bin,i,j,k; int lastbin = 0; /* Map the exponents into dBs */ for (bin = start; bin < end; bin++) { psd[bin] = (3072 - (exps[bin] << 7)); } /* Integrate the psd function over each bit allocation band */ j = start; k = mpeg3_masktab[start]; do { lastbin = mpeg3_min(mpeg3_bndtab[k] + mpeg3_bndsz[k], end); bndpsd[k] = psd[j]; j++; for(i = j; i < lastbin; i++) { bndpsd[k] = logadd(bndpsd[k], psd[j]); j++; } k++; }while(end > lastbin); } void mpeg3audio_ac3_ba_compute_excitation(mpeg3audio_t *audio, int start, int end, int fgain, int fastleak, int slowleak, int is_lfe, short bndpsd[], short excite[]) { int bin; int bndstrt; int bndend; int lowcomp = 0; int begin = 0; /* Compute excitation function */ bndstrt = mpeg3_masktab[start]; bndend = mpeg3_masktab[end - 1] + 1; if(bndstrt == 0) /* For fbw and lfe channels */ { lowcomp = mpeg3audio_ac3_calc_lowcomp(lowcomp, bndpsd[0], bndpsd[1], 0); excite[0] = bndpsd[0] - fgain - lowcomp; lowcomp = mpeg3audio_ac3_calc_lowcomp(lowcomp, bndpsd[1], bndpsd[2], 1); excite[1] = bndpsd[1] - fgain - lowcomp; begin = 7 ; /* Note: Do not call mpeg3audio_ac3_calc_lowcomp() for the last band of the lfe channel, (bin = 6) */ for (bin = 2; bin < 7; bin++) { if(!(is_lfe && (bin == 6))) lowcomp = mpeg3audio_ac3_calc_lowcomp(lowcomp, bndpsd[bin], bndpsd[bin+1], bin); fastleak = bndpsd[bin] - fgain; slowleak = bndpsd[bin] - audio->ac3_bit_allocation.sgain; excite[bin] = fastleak - lowcomp; if(!(is_lfe && (bin == 6))) { if(bndpsd[bin] <= bndpsd[bin+1]) { begin = bin + 1 ; break; } } } for (bin = begin; bin < mpeg3_min(bndend, 22); bin++) { if (!(is_lfe && (bin == 6))) lowcomp = mpeg3audio_ac3_calc_lowcomp(lowcomp, bndpsd[bin], bndpsd[bin+1], bin); fastleak -= audio->ac3_bit_allocation.fdecay; fastleak = mpeg3_max(fastleak, bndpsd[bin] - fgain); slowleak -= audio->ac3_bit_allocation.sdecay; slowleak = mpeg3_max(slowleak, bndpsd[bin] - audio->ac3_bit_allocation.sgain); excite[bin] = mpeg3_max(fastleak - lowcomp, slowleak); } begin = 22; } else /* For coupling channel */ { begin = bndstrt; } for (bin = begin; bin < bndend; bin++) { fastleak -= audio->ac3_bit_allocation.fdecay; fastleak = mpeg3_max(fastleak, bndpsd[bin] - fgain); slowleak -= audio->ac3_bit_allocation.sdecay; slowleak = mpeg3_max(slowleak, bndpsd[bin] - audio->ac3_bit_allocation.sgain); excite[bin] = mpeg3_max(fastleak, slowleak) ; } } void mpeg3audio_ac3_ba_compute_mask(mpeg3audio_t *audio, int start, int end, int fscod, int deltbae, int deltnseg, short deltoffst[], short deltba[], short deltlen[], short excite[], short mask[]) { int bin, k; int bndstrt; int bndend; int delta; bndstrt = mpeg3_masktab[start]; bndend = mpeg3_masktab[end - 1] + 1; /* Compute the masking curve */ for (bin = bndstrt; bin < bndend; bin++) { if (audio->ac3_bit_allocation.bndpsd[bin] < audio->ac3_bit_allocation.dbknee) { excite[bin] += ((audio->ac3_bit_allocation.dbknee - audio->ac3_bit_allocation.bndpsd[bin]) >> 2); } mask[bin] = mpeg3_max(excite[bin], mpeg3_hth[fscod][bin]); } /* Perform delta bit modulation if necessary */ if ((deltbae == DELTA_BIT_REUSE) || (deltbae == DELTA_BIT_NEW)) { int band = 0; int seg = 0; for (seg = 0; seg < deltnseg + 1; seg++) { band += deltoffst[seg]; if (deltba[seg] >= 4) { delta = (deltba[seg] - 3) << 7; } else { delta = (deltba[seg] - 4) << 7; } for (k = 0; k < deltlen[seg]; k++) { mask[band] += delta; band++; } } } } void mpeg3audio_ac3_ba_compute_bap(mpeg3audio_t *audio, int start, int end, int snroffset, short psd[], short mask[], short bap[]) { int i, j, k; short lastbin = 0; short address = 0; /* Compute the bit allocation pointer for each bin */ i = start; j = mpeg3_masktab[start]; do { lastbin = mpeg3_min(mpeg3_bndtab[j] + mpeg3_bndsz[j], end); mask[j] -= snroffset; mask[j] -= audio->ac3_bit_allocation.floor; if(mask[j] < 0) mask[j] = 0; mask[j] &= 0x1fe0; mask[j] += audio->ac3_bit_allocation.floor; for(k = i; k < lastbin; k++) { address = (psd[i] - mask[j]) >> 5; address = mpeg3_min(63, mpeg3_max(0, address)); bap[i] = mpeg3_baptab[address]; i++; } j++; }while (end > lastbin); } int mpeg3audio_ac3_bit_allocate(mpeg3audio_t *audio, unsigned int fscod, mpeg3_ac3bsi_t *bsi, mpeg3_ac3audblk_t *audblk) { int result = 0; int i; int fgain; int snroffset; int start; int end; int fastleak; int slowleak; /*printf("mpeg3audio_ac3_bit_allocate %d %d %d %d %d\n", audblk->sdcycod, audblk->fdcycod, audblk->sgaincod, audblk->dbpbcod, audblk->floorcod); */ /* Only perform bit_allocation if the exponents have changed or we * have new sideband information */ if(audblk->chexpstr[0] == 0 && audblk->chexpstr[1] == 0 && audblk->chexpstr[2] == 0 && audblk->chexpstr[3] == 0 && audblk->chexpstr[4] == 0 && audblk->cplexpstr == 0 && audblk->lfeexpstr == 0 && audblk->baie == 0 && audblk->snroffste == 0 && audblk->deltbaie == 0) return 0; /* Do some setup before we do the bit alloc */ audio->ac3_bit_allocation.sdecay = mpeg3_slowdec[audblk->sdcycod]; audio->ac3_bit_allocation.fdecay = mpeg3_fastdec[audblk->fdcycod]; audio->ac3_bit_allocation.sgain = mpeg3_slowgain[audblk->sgaincod]; audio->ac3_bit_allocation.dbknee = mpeg3_dbpbtab[audblk->dbpbcod]; audio->ac3_bit_allocation.floor = mpeg3_floortab[audblk->floorcod]; /* if all the SNR offset constants are zero then the whole block is zero */ if(!audblk->csnroffst && !audblk->fsnroffst[0] && !audblk->fsnroffst[1] && !audblk->fsnroffst[2] && !audblk->fsnroffst[3] && !audblk->fsnroffst[4] && !audblk->cplfsnroffst && !audblk->lfefsnroffst) { memset(audblk->fbw_bap, 0, sizeof(short) * 256 * 5); memset(audblk->cpl_bap, 0, sizeof(short) * 256); memset(audblk->lfe_bap, 0, sizeof(short) * 7); return 0; } for(i = 0; i < bsi->nfchans; i++) { start = 0; end = audblk->endmant[i]; fgain = mpeg3_fastgain[audblk->fgaincod[i]]; snroffset = (((audblk->csnroffst - 15) << 4) + audblk->fsnroffst[i]) << 2 ; fastleak = 0; slowleak = 0; mpeg3audio_ac3_ba_compute_psd(start, end, (short*)audblk->fbw_exp[i], audio->ac3_bit_allocation.psd, audio->ac3_bit_allocation.bndpsd); mpeg3audio_ac3_ba_compute_excitation(audio, start, end , fgain, fastleak, slowleak, 0, audio->ac3_bit_allocation.bndpsd, audio->ac3_bit_allocation.excite); mpeg3audio_ac3_ba_compute_mask(audio, start, end, fscod, audblk->deltbae[i], audblk->deltnseg[i], (short*)audblk->deltoffst[i], (short*)audblk->deltba[i], (short*)audblk->deltlen[i], audio->ac3_bit_allocation.excite, audio->ac3_bit_allocation.mask); mpeg3audio_ac3_ba_compute_bap(audio, start, end, snroffset, audio->ac3_bit_allocation.psd, audio->ac3_bit_allocation.mask, (short*)audblk->fbw_bap[i]); } if(audblk->cplinu) { start = audblk->cplstrtmant; end = audblk->cplendmant; fgain = mpeg3_fastgain[audblk->cplfgaincod]; snroffset = (((audblk->csnroffst - 15) << 4) + audblk->cplfsnroffst) << 2 ; fastleak = (audblk->cplfleak << 8) + 768; slowleak = (audblk->cplsleak << 8) + 768; mpeg3audio_ac3_ba_compute_psd(start, end, (short*)audblk->cpl_exp, audio->ac3_bit_allocation.psd, audio->ac3_bit_allocation.bndpsd); mpeg3audio_ac3_ba_compute_excitation(audio, start, end , fgain, fastleak, slowleak, 0, audio->ac3_bit_allocation.bndpsd, audio->ac3_bit_allocation.excite); mpeg3audio_ac3_ba_compute_mask(audio, start, end, fscod, audblk->cpldeltbae, audblk->cpldeltnseg, (short*)audblk->cpldeltoffst, (short*)audblk->cpldeltba, (short*)audblk->cpldeltlen, audio->ac3_bit_allocation.excite, audio->ac3_bit_allocation.mask); mpeg3audio_ac3_ba_compute_bap(audio, start, end, snroffset, audio->ac3_bit_allocation.psd, audio->ac3_bit_allocation.mask, (short*)audblk->cpl_bap); } if(bsi->lfeon) { start = 0; end = 7; fgain = mpeg3_fastgain[audblk->lfefgaincod]; snroffset = (((audblk->csnroffst - 15) << 4) + audblk->lfefsnroffst) << 2 ; fastleak = 0; slowleak = 0; mpeg3audio_ac3_ba_compute_psd(start, end, (short*)audblk->lfe_exp, audio->ac3_bit_allocation.psd, audio->ac3_bit_allocation.bndpsd); mpeg3audio_ac3_ba_compute_excitation(audio, start, end , fgain, fastleak, slowleak, 1, audio->ac3_bit_allocation.bndpsd, audio->ac3_bit_allocation.excite); /* Perform no delta bit allocation for lfe */ mpeg3audio_ac3_ba_compute_mask(audio, start, end, fscod, 2, 0, 0, 0, 0, audio->ac3_bit_allocation.excite, audio->ac3_bit_allocation.mask); mpeg3audio_ac3_ba_compute_bap(audio, start, end, snroffset, audio->ac3_bit_allocation.psd, audio->ac3_bit_allocation.mask, (short*)audblk->lfe_bap); } return result; } libmpeg3-1.5.4/audio/c_flags0000755000175000017500000000001507742725645016102 0ustar enderender00000000000000echo $CFLAGS libmpeg3-1.5.4/audio/dct.c0000644000175000017500000004432007742725645015503 0ustar enderender00000000000000/* * * This file is part of libmpeg3 * * libmpeg3 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * libmpeg3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ /* * Discrete Cosine Tansform (DCT) for subband synthesis * optimized for machines with no auto-increment. * The performance is highly compiler dependend. Maybe * the dct64.c version for 'normal' processor may be faster * even for Intel processors. */ #include "mpeg3private.h" #include "mpeg3protos.h" #include "tables.h" #include int mpeg3audio_dct64_1(float *out0, float *out1, float *b1, float *b2, float *samples) { register float *costab = mpeg3_pnts[0]; b1[0x00] = samples[0x00] + samples[0x1F]; b1[0x01] = samples[0x01] + samples[0x1E]; b1[0x1F] = (samples[0x00] - samples[0x1F]) * costab[0x0]; b1[0x1E] = (samples[0x01] - samples[0x1E]) * costab[0x1]; b1[0x02] = samples[0x02] + samples[0x1D]; b1[0x03] = samples[0x03] + samples[0x1C]; b1[0x1D] = (samples[0x02] - samples[0x1D]) * costab[0x2]; b1[0x1C] = (samples[0x03] - samples[0x1C]) * costab[0x3]; b1[0x04] = samples[0x04] + samples[0x1B]; b1[0x05] = samples[0x05] + samples[0x1A]; b1[0x1B] = (samples[0x04] - samples[0x1B]) * costab[0x4]; b1[0x1A] = (samples[0x05] - samples[0x1A]) * costab[0x5]; b1[0x06] = samples[0x06] + samples[0x19]; b1[0x07] = samples[0x07] + samples[0x18]; b1[0x19] = (samples[0x06] - samples[0x19]) * costab[0x6]; b1[0x18] = (samples[0x07] - samples[0x18]) * costab[0x7]; b1[0x08] = samples[0x08] + samples[0x17]; b1[0x09] = samples[0x09] + samples[0x16]; b1[0x17] = (samples[0x08] - samples[0x17]) * costab[0x8]; b1[0x16] = (samples[0x09] - samples[0x16]) * costab[0x9]; b1[0x0A] = samples[0x0A] + samples[0x15]; b1[0x0B] = samples[0x0B] + samples[0x14]; b1[0x15] = (samples[0x0A] - samples[0x15]) * costab[0xA]; b1[0x14] = (samples[0x0B] - samples[0x14]) * costab[0xB]; b1[0x0C] = samples[0x0C] + samples[0x13]; b1[0x0D] = samples[0x0D] + samples[0x12]; b1[0x13] = (samples[0x0C] - samples[0x13]) * costab[0xC]; b1[0x12] = (samples[0x0D] - samples[0x12]) * costab[0xD]; b1[0x0E] = samples[0x0E] + samples[0x11]; b1[0x0F] = samples[0x0F] + samples[0x10]; b1[0x11] = (samples[0x0E] - samples[0x11]) * costab[0xE]; b1[0x10] = (samples[0x0F] - samples[0x10]) * costab[0xF]; costab = mpeg3_pnts[1]; b2[0x00] = b1[0x00] + b1[0x0F]; b2[0x01] = b1[0x01] + b1[0x0E]; b2[0x0F] = (b1[0x00] - b1[0x0F]) * costab[0]; b2[0x0E] = (b1[0x01] - b1[0x0E]) * costab[1]; b2[0x02] = b1[0x02] + b1[0x0D]; b2[0x03] = b1[0x03] + b1[0x0C]; b2[0x0D] = (b1[0x02] - b1[0x0D]) * costab[2]; b2[0x0C] = (b1[0x03] - b1[0x0C]) * costab[3]; b2[0x04] = b1[0x04] + b1[0x0B]; b2[0x05] = b1[0x05] + b1[0x0A]; b2[0x0B] = (b1[0x04] - b1[0x0B]) * costab[4]; b2[0x0A] = (b1[0x05] - b1[0x0A]) * costab[5]; b2[0x06] = b1[0x06] + b1[0x09]; b2[0x07] = b1[0x07] + b1[0x08]; b2[0x09] = (b1[0x06] - b1[0x09]) * costab[6]; b2[0x08] = (b1[0x07] - b1[0x08]) * costab[7]; /* */ b2[0x10] = b1[0x10] + b1[0x1F]; b2[0x11] = b1[0x11] + b1[0x1E]; b2[0x1F] = (b1[0x1F] - b1[0x10]) * costab[0]; b2[0x1E] = (b1[0x1E] - b1[0x11]) * costab[1]; b2[0x12] = b1[0x12] + b1[0x1D]; b2[0x13] = b1[0x13] + b1[0x1C]; b2[0x1D] = (b1[0x1D] - b1[0x12]) * costab[2]; b2[0x1C] = (b1[0x1C] - b1[0x13]) * costab[3]; b2[0x14] = b1[0x14] + b1[0x1B]; b2[0x15] = b1[0x15] + b1[0x1A]; b2[0x1B] = (b1[0x1B] - b1[0x14]) * costab[4]; b2[0x1A] = (b1[0x1A] - b1[0x15]) * costab[5]; b2[0x16] = b1[0x16] + b1[0x19]; b2[0x17] = b1[0x17] + b1[0x18]; b2[0x19] = (b1[0x19] - b1[0x16]) * costab[6]; b2[0x18] = (b1[0x18] - b1[0x17]) * costab[7]; costab = mpeg3_pnts[2]; b1[0x00] = b2[0x00] + b2[0x07]; b1[0x07] = (b2[0x00] - b2[0x07]) * costab[0]; b1[0x01] = b2[0x01] + b2[0x06]; b1[0x06] = (b2[0x01] - b2[0x06]) * costab[1]; b1[0x02] = b2[0x02] + b2[0x05]; b1[0x05] = (b2[0x02] - b2[0x05]) * costab[2]; b1[0x03] = b2[0x03] + b2[0x04]; b1[0x04] = (b2[0x03] - b2[0x04]) * costab[3]; b1[0x08] = b2[0x08] + b2[0x0F]; b1[0x0F] = (b2[0x0F] - b2[0x08]) * costab[0]; b1[0x09] = b2[0x09] + b2[0x0E]; b1[0x0E] = (b2[0x0E] - b2[0x09]) * costab[1]; b1[0x0A] = b2[0x0A] + b2[0x0D]; b1[0x0D] = (b2[0x0D] - b2[0x0A]) * costab[2]; b1[0x0B] = b2[0x0B] + b2[0x0C]; b1[0x0C] = (b2[0x0C] - b2[0x0B]) * costab[3]; b1[0x10] = b2[0x10] + b2[0x17]; b1[0x17] = (b2[0x10] - b2[0x17]) * costab[0]; b1[0x11] = b2[0x11] + b2[0x16]; b1[0x16] = (b2[0x11] - b2[0x16]) * costab[1]; b1[0x12] = b2[0x12] + b2[0x15]; b1[0x15] = (b2[0x12] - b2[0x15]) * costab[2]; b1[0x13] = b2[0x13] + b2[0x14]; b1[0x14] = (b2[0x13] - b2[0x14]) * costab[3]; b1[0x18] = b2[0x18] + b2[0x1F]; b1[0x1F] = (b2[0x1F] - b2[0x18]) * costab[0]; b1[0x19] = b2[0x19] + b2[0x1E]; b1[0x1E] = (b2[0x1E] - b2[0x19]) * costab[1]; b1[0x1A] = b2[0x1A] + b2[0x1D]; b1[0x1D] = (b2[0x1D] - b2[0x1A]) * costab[2]; b1[0x1B] = b2[0x1B] + b2[0x1C]; b1[0x1C] = (b2[0x1C] - b2[0x1B]) * costab[3]; { register float const cos0 = mpeg3_pnts[3][0]; register float const cos1 = mpeg3_pnts[3][1]; b2[0x00] = b1[0x00] + b1[0x03]; b2[0x03] = (b1[0x00] - b1[0x03]) * cos0; b2[0x01] = b1[0x01] + b1[0x02]; b2[0x02] = (b1[0x01] - b1[0x02]) * cos1; b2[0x04] = b1[0x04] + b1[0x07]; b2[0x07] = (b1[0x07] - b1[0x04]) * cos0; b2[0x05] = b1[0x05] + b1[0x06]; b2[0x06] = (b1[0x06] - b1[0x05]) * cos1; b2[0x08] = b1[0x08] + b1[0x0B]; b2[0x0B] = (b1[0x08] - b1[0x0B]) * cos0; b2[0x09] = b1[0x09] + b1[0x0A]; b2[0x0A] = (b1[0x09] - b1[0x0A]) * cos1; b2[0x0C] = b1[0x0C] + b1[0x0F]; b2[0x0F] = (b1[0x0F] - b1[0x0C]) * cos0; b2[0x0D] = b1[0x0D] + b1[0x0E]; b2[0x0E] = (b1[0x0E] - b1[0x0D]) * cos1; b2[0x10] = b1[0x10] + b1[0x13]; b2[0x13] = (b1[0x10] - b1[0x13]) * cos0; b2[0x11] = b1[0x11] + b1[0x12]; b2[0x12] = (b1[0x11] - b1[0x12]) * cos1; b2[0x14] = b1[0x14] + b1[0x17]; b2[0x17] = (b1[0x17] - b1[0x14]) * cos0; b2[0x15] = b1[0x15] + b1[0x16]; b2[0x16] = (b1[0x16] - b1[0x15]) * cos1; b2[0x18] = b1[0x18] + b1[0x1B]; b2[0x1B] = (b1[0x18] - b1[0x1B]) * cos0; b2[0x19] = b1[0x19] + b1[0x1A]; b2[0x1A] = (b1[0x19] - b1[0x1A]) * cos1; b2[0x1C] = b1[0x1C] + b1[0x1F]; b2[0x1F] = (b1[0x1F] - b1[0x1C]) * cos0; b2[0x1D] = b1[0x1D] + b1[0x1E]; b2[0x1E] = (b1[0x1E] - b1[0x1D]) * cos1; } { register float const cos0 = mpeg3_pnts[4][0]; b1[0x00] = b2[0x00] + b2[0x01]; b1[0x01] = (b2[0x00] - b2[0x01]) * cos0; b1[0x02] = b2[0x02] + b2[0x03]; b1[0x03] = (b2[0x03] - b2[0x02]) * cos0; b1[0x02] += b1[0x03]; b1[0x04] = b2[0x04] + b2[0x05]; b1[0x05] = (b2[0x04] - b2[0x05]) * cos0; b1[0x06] = b2[0x06] + b2[0x07]; b1[0x07] = (b2[0x07] - b2[0x06]) * cos0; b1[0x06] += b1[0x07]; b1[0x04] += b1[0x06]; b1[0x06] += b1[0x05]; b1[0x05] += b1[0x07]; b1[0x08] = b2[0x08] + b2[0x09]; b1[0x09] = (b2[0x08] - b2[0x09]) * cos0; b1[0x0A] = b2[0x0A] + b2[0x0B]; b1[0x0B] = (b2[0x0B] - b2[0x0A]) * cos0; b1[0x0A] += b1[0x0B]; b1[0x0C] = b2[0x0C] + b2[0x0D]; b1[0x0D] = (b2[0x0C] - b2[0x0D]) * cos0; b1[0x0E] = b2[0x0E] + b2[0x0F]; b1[0x0F] = (b2[0x0F] - b2[0x0E]) * cos0; b1[0x0E] += b1[0x0F]; b1[0x0C] += b1[0x0E]; b1[0x0E] += b1[0x0D]; b1[0x0D] += b1[0x0F]; b1[0x10] = b2[0x10] + b2[0x11]; b1[0x11] = (b2[0x10] - b2[0x11]) * cos0; b1[0x12] = b2[0x12] + b2[0x13]; b1[0x13] = (b2[0x13] - b2[0x12]) * cos0; b1[0x12] += b1[0x13]; b1[0x14] = b2[0x14] + b2[0x15]; b1[0x15] = (b2[0x14] - b2[0x15]) * cos0; b1[0x16] = b2[0x16] + b2[0x17]; b1[0x17] = (b2[0x17] - b2[0x16]) * cos0; b1[0x16] += b1[0x17]; b1[0x14] += b1[0x16]; b1[0x16] += b1[0x15]; b1[0x15] += b1[0x17]; b1[0x18] = b2[0x18] + b2[0x19]; b1[0x19] = (b2[0x18] - b2[0x19]) * cos0; b1[0x1A] = b2[0x1A] + b2[0x1B]; b1[0x1B] = (b2[0x1B] - b2[0x1A]) * cos0; b1[0x1A] += b1[0x1B]; b1[0x1C] = b2[0x1C] + b2[0x1D]; b1[0x1D] = (b2[0x1C] - b2[0x1D]) * cos0; b1[0x1E] = b2[0x1E] + b2[0x1F]; b1[0x1F] = (b2[0x1F] - b2[0x1E]) * cos0; b1[0x1E] += b1[0x1F]; b1[0x1C] += b1[0x1E]; b1[0x1E] += b1[0x1D]; b1[0x1D] += b1[0x1F]; } out0[0x10*16] = b1[0x00]; out0[0x10*12] = b1[0x04]; out0[0x10* 8] = b1[0x02]; out0[0x10* 4] = b1[0x06]; out0[0x10* 0] = b1[0x01]; out1[0x10* 0] = b1[0x01]; out1[0x10* 4] = b1[0x05]; out1[0x10* 8] = b1[0x03]; out1[0x10*12] = b1[0x07]; out0[0x10*14] = b1[0x08] + b1[0x0C]; out0[0x10*10] = b1[0x0C] + b1[0x0a]; out0[0x10* 6] = b1[0x0A] + b1[0x0E]; out0[0x10* 2] = b1[0x0E] + b1[0x09]; out1[0x10* 2] = b1[0x09] + b1[0x0D]; out1[0x10* 6] = b1[0x0D] + b1[0x0B]; out1[0x10*10] = b1[0x0B] + b1[0x0F]; out1[0x10*14] = b1[0x0F]; { register float tmp; tmp = b1[0x18] + b1[0x1C]; out0[0x10*15] = tmp + b1[0x10]; out0[0x10*13] = tmp + b1[0x14]; tmp = b1[0x1C] + b1[0x1A]; out0[0x10*11] = tmp + b1[0x14]; out0[0x10* 9] = tmp + b1[0x12]; tmp = b1[0x1A] + b1[0x1E]; out0[0x10* 7] = tmp + b1[0x12]; out0[0x10* 5] = tmp + b1[0x16]; tmp = b1[0x1E] + b1[0x19]; out0[0x10* 3] = tmp + b1[0x16]; out0[0x10* 1] = tmp + b1[0x11]; tmp = b1[0x19] + b1[0x1D]; out1[0x10* 1] = tmp + b1[0x11]; out1[0x10* 3] = tmp + b1[0x15]; tmp = b1[0x1D] + b1[0x1B]; out1[0x10* 5] = tmp + b1[0x15]; out1[0x10* 7] = tmp + b1[0x13]; tmp = b1[0x1B] + b1[0x1F]; out1[0x10* 9] = tmp + b1[0x13]; out1[0x10*11] = tmp + b1[0x17]; out1[0x10*13] = b1[0x17] + b1[0x1F]; out1[0x10*15] = b1[0x1F]; } return 0; } /* * the call via dct64 is a trick to force GCC to use * (new) registers for the b1,b2 pointer to the bufs[xx] field */ int mpeg3audio_dct64(float *a, float *b, float *c) { float bufs[0x40]; return mpeg3audio_dct64_1(a, b, bufs, bufs + 0x20, c); } /*//////////////////////////////////////////////////////////////// */ /* */ /* 9 Point Inverse Discrete Cosine Transform */ /* */ /* This piece of code is Copyright 1997 Mikko Tommila and is freely usable */ /* by anybody. The algorithm itself is of course in the public domain. */ /* */ /* Again derived heuristically from the 9-point WFTA. */ /* */ /* The algorithm is optimized (?) for speed, not for small rounding errors or */ /* good readability. */ /* */ /* 36 additions, 11 multiplications */ /* */ /* Again this is very likely sub-optimal. */ /* */ /* The code is optimized to use a minimum number of temporary variables, */ /* so it should compile quite well even on 8-register Intel x86 processors. */ /* This makes the code quite obfuscated and very difficult to understand. */ /* */ /* References: */ /* [1] S. Winograd: "On Computing the Discrete Fourier Transform", */ /* Mathematics of Computation, Volume 32, Number 141, January 1978, */ /* Pages 175-199 */ /*------------------------------------------------------------------*/ /* */ /* Function: Calculation of the inverse MDCT */ /* */ /*------------------------------------------------------------------*/ int mpeg3audio_dct36(float *inbuf, float *o1, float *o2, float *wintab, float *tsbuf) { float tmp[18]; { register float *in = inbuf; in[17]+=in[16]; in[16]+=in[15]; in[15]+=in[14]; in[14]+=in[13]; in[13]+=in[12]; in[12]+=in[11]; in[11]+=in[10]; in[10]+=in[9]; in[9] +=in[8]; in[8] +=in[7]; in[7] +=in[6]; in[6] +=in[5]; in[5] +=in[4]; in[4] +=in[3]; in[3] +=in[2]; in[2] +=in[1]; in[1] +=in[0]; in[17]+=in[15]; in[15]+=in[13]; in[13]+=in[11]; in[11]+=in[9]; in[9] +=in[7]; in[7] +=in[5]; in[5] +=in[3]; in[3] +=in[1]; { float t3; { float t0, t1, t2; t0 = mpeg3_COS6_2 * (in[8] + in[16] - in[4]); t1 = mpeg3_COS6_2 * in[12]; t3 = in[0]; t2 = t3 - t1 - t1; tmp[1] = tmp[7] = t2 - t0; tmp[4] = t2 + t0 + t0; t3 += t1; t2 = mpeg3_COS6_1 * (in[10] + in[14] - in[2]); tmp[1] -= t2; tmp[7] += t2; } { float t0, t1, t2; t0 = mpeg3_cos9[0] * (in[4] + in[8] ); t1 = mpeg3_cos9[1] * (in[8] - in[16]); t2 = mpeg3_cos9[2] * (in[4] + in[16]); tmp[2] = tmp[6] = t3 - t0 - t2; tmp[0] = tmp[8] = t3 + t0 + t1; tmp[3] = tmp[5] = t3 - t1 + t2; } } { float t1, t2, t3; t1 = mpeg3_cos18[0] * (in[2] + in[10]); t2 = mpeg3_cos18[1] * (in[10] - in[14]); t3 = mpeg3_COS6_1 * in[6]; { float t0 = t1 + t2 + t3; tmp[0] += t0; tmp[8] -= t0; } t2 -= t3; t1 -= t3; t3 = mpeg3_cos18[2] * (in[2] + in[14]); t1 += t3; tmp[3] += t1; tmp[5] -= t1; t2 -= t3; tmp[2] += t2; tmp[6] -= t2; } { float t0, t1, t2, t3, t4, t5, t6, t7; t1 = mpeg3_COS6_2 * in[13]; t2 = mpeg3_COS6_2 * (in[9] + in[17] - in[5]); t3 = in[1] + t1; t4 = in[1] - t1 - t1; t5 = t4 - t2; t0 = mpeg3_cos9[0] * (in[5] + in[9]); t1 = mpeg3_cos9[1] * (in[9] - in[17]); tmp[13] = (t4 + t2 + t2) * mpeg3_tfcos36[17-13]; t2 = mpeg3_cos9[2] * (in[5] + in[17]); t6 = t3 - t0 - t2; t0 += t3 + t1; t3 += t2 - t1; t2 = mpeg3_cos18[0] * (in[3] + in[11]); t4 = mpeg3_cos18[1] * (in[11] - in[15]); t7 = mpeg3_COS6_1 * in[7]; t1 = t2 + t4 + t7; tmp[17] = (t0 + t1) * mpeg3_tfcos36[17-17]; tmp[9] = (t0 - t1) * mpeg3_tfcos36[17-9]; t1 = mpeg3_cos18[2] * (in[3] + in[15]); t2 += t1 - t7; tmp[14] = (t3 + t2) * mpeg3_tfcos36[17-14]; t0 = mpeg3_COS6_1 * (in[11] + in[15] - in[3]); tmp[12] = (t3 - t2) * mpeg3_tfcos36[17-12]; t4 -= t1 + t7; tmp[16] = (t5 - t0) * mpeg3_tfcos36[17-16]; tmp[10] = (t5 + t0) * mpeg3_tfcos36[17-10]; tmp[15] = (t6 + t4) * mpeg3_tfcos36[17-15]; tmp[11] = (t6 - t4) * mpeg3_tfcos36[17-11]; } #define MACRO(v) \ { \ float tmpval; \ tmpval = tmp[(v)] + tmp[17-(v)]; \ out2[9+(v)] = tmpval * w[27+(v)]; \ out2[8-(v)] = tmpval * w[26-(v)]; \ tmpval = tmp[(v)] - tmp[17-(v)]; \ ts[SBLIMIT*(8-(v))] = out1[8-(v)] + tmpval * w[8-(v)]; \ ts[SBLIMIT*(9+(v))] = out1[9+(v)] + tmpval * w[9+(v)]; \ } { register float *out2 = o2; register float *w = wintab; register float *out1 = o1; register float *ts = tsbuf; MACRO(0); MACRO(1); MACRO(2); MACRO(3); MACRO(4); MACRO(5); MACRO(6); MACRO(7); MACRO(8); } } return 0; } /* * new DCT12 */ int mpeg3audio_dct12(float *in,float *rawout1,float *rawout2,register float *wi,register float *ts) { #define DCT12_PART1 \ in5 = in[5*3]; \ in5 += (in4 = in[4*3]); \ in4 += (in3 = in[3*3]); \ in3 += (in2 = in[2*3]); \ in2 += (in1 = in[1*3]); \ in1 += (in0 = in[0*3]); \ \ in5 += in3; in3 += in1; \ \ in2 *= mpeg3_COS6_1; \ in3 *= mpeg3_COS6_1; \ #define DCT12_PART2 \ in0 += in4 * mpeg3_COS6_2; \ \ in4 = in0 + in2; \ in0 -= in2; \ \ in1 += in5 * mpeg3_COS6_2; \ \ in5 = (in1 + in3) * mpeg3_tfcos12[0]; \ in1 = (in1 - in3) * mpeg3_tfcos12[2]; \ \ in3 = in4 + in5; \ in4 -= in5; \ \ in2 = in0 + in1; \ in0 -= in1; { float in0,in1,in2,in3,in4,in5; register float *out1 = rawout1; ts[SBLIMIT*0] = out1[0]; ts[SBLIMIT*1] = out1[1]; ts[SBLIMIT*2] = out1[2]; ts[SBLIMIT*3] = out1[3]; ts[SBLIMIT*4] = out1[4]; ts[SBLIMIT*5] = out1[5]; DCT12_PART1 { float tmp0,tmp1 = (in0 - in4); { float tmp2 = (in1 - in5) * mpeg3_tfcos12[1]; tmp0 = tmp1 + tmp2; tmp1 -= tmp2; } ts[(17-1)*SBLIMIT] = out1[17-1] + tmp0 * wi[11-1]; ts[(12+1)*SBLIMIT] = out1[12+1] + tmp0 * wi[6+1]; ts[(6 +1)*SBLIMIT] = out1[6 +1] + tmp1 * wi[1]; ts[(11-1)*SBLIMIT] = out1[11-1] + tmp1 * wi[5-1]; } DCT12_PART2 ts[(17-0)*SBLIMIT] = out1[17-0] + in2 * wi[11-0]; ts[(12+0)*SBLIMIT] = out1[12+0] + in2 * wi[6+0]; ts[(12+2)*SBLIMIT] = out1[12+2] + in3 * wi[6+2]; ts[(17-2)*SBLIMIT] = out1[17-2] + in3 * wi[11-2]; ts[(6+0)*SBLIMIT] = out1[6+0] + in0 * wi[0]; ts[(11-0)*SBLIMIT] = out1[11-0] + in0 * wi[5-0]; ts[(6+2)*SBLIMIT] = out1[6+2] + in4 * wi[2]; ts[(11-2)*SBLIMIT] = out1[11-2] + in4 * wi[5-2]; } in++; { float in0,in1,in2,in3,in4,in5; register float *out2 = rawout2; DCT12_PART1 { float tmp0,tmp1 = (in0 - in4); { float tmp2 = (in1 - in5) * mpeg3_tfcos12[1]; tmp0 = tmp1 + tmp2; tmp1 -= tmp2; } out2[5-1] = tmp0 * wi[11-1]; out2[0+1] = tmp0 * wi[6+1]; ts[(12+1)*SBLIMIT] += tmp1 * wi[1]; ts[(17-1)*SBLIMIT] += tmp1 * wi[5-1]; } DCT12_PART2 out2[5-0] = in2 * wi[11-0]; out2[0+0] = in2 * wi[6+0]; out2[0+2] = in3 * wi[6+2]; out2[5-2] = in3 * wi[11-2]; ts[(12+0)*SBLIMIT] += in0 * wi[0]; ts[(17-0)*SBLIMIT] += in0 * wi[5-0]; ts[(12+2)*SBLIMIT] += in4 * wi[2]; ts[(17-2)*SBLIMIT] += in4 * wi[5-2]; } in++; { float in0,in1,in2,in3,in4,in5; register float *out2 = rawout2; out2[12]=out2[13]=out2[14]=out2[15]=out2[16]=out2[17]=0.0; DCT12_PART1 { float tmp0,tmp1 = (in0 - in4); { float tmp2 = (in1 - in5) * mpeg3_tfcos12[1]; tmp0 = tmp1 + tmp2; tmp1 -= tmp2; } out2[11-1] = tmp0 * wi[11-1]; out2[6 +1] = tmp0 * wi[6+1]; out2[0+1] += tmp1 * wi[1]; out2[5-1] += tmp1 * wi[5-1]; } DCT12_PART2 out2[11-0] = in2 * wi[11-0]; out2[6 +0] = in2 * wi[6+0]; out2[6 +2] = in3 * wi[6+2]; out2[11-2] = in3 * wi[11-2]; out2[0+0] += in0 * wi[0]; out2[5-0] += in0 * wi[5-0]; out2[0+2] += in4 * wi[2]; out2[5-2] += in4 * wi[5-2]; } return 0; } libmpeg3-1.5.4/audio/exponents.c0000644000175000017500000000666607742725645016767 0ustar enderender00000000000000/* * * exponents.c Copyright (C) Aaron Holtzman - May 1999 * * This file is part of libmpeg3 * * libmpeg3 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * libmpeg3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #define MIN(x, y) ((x) > (y) ? (y) : (x)) #include "mpeg3audio.h" #include /* Exponent defines */ #define UNPACK_FBW 1 #define UNPACK_CPL 2 #define UNPACK_LFE 4 static inline int mpeg3audio_ac3_exp_unpack_ch(unsigned int type, unsigned int expstr, unsigned int ngrps, unsigned int initial_exp, unsigned short exps[], unsigned short *dest) { int i, j; int exp_acc; int exp_1, exp_2, exp_3; if(expstr == MPEG3_EXP_REUSE) return 0; /* Handle the initial absolute exponent */ exp_acc = initial_exp; j = 0; /* In the case of a fbw channel then the initial absolute value is * also an exponent */ if(type != UNPACK_CPL) dest[j++] = exp_acc; /* Loop through the groups and fill the dest array appropriately */ for(i = 0; i < ngrps; i++) { if(exps[i] > 124) { // fprintf(stderr, "mpeg3audio_ac3_exp_unpack_ch: Invalid exponent %d\n", exps[i]); return 1; } exp_1 = exps[i] / 25; exp_2 = (exps[i] % 25) / 5; exp_3 = (exps[i] % 25) % 5; exp_acc += (exp_1 - 2); switch(expstr) { case MPEG3_EXP_D45: j = MIN(255, j); dest[j++] = exp_acc; j = MIN(255, j); dest[j++] = exp_acc; case MPEG3_EXP_D25: j = MIN(255, j); dest[j++] = exp_acc; case MPEG3_EXP_D15: j = MIN(255, j); dest[j++] = exp_acc; } exp_acc += (exp_2 - 2); switch(expstr) { case MPEG3_EXP_D45: j = MIN(255, j); dest[j++] = exp_acc; j = MIN(255, j); dest[j++] = exp_acc; case MPEG3_EXP_D25: j = MIN(255, j); dest[j++] = exp_acc; case MPEG3_EXP_D15: j = MIN(255, j); dest[j++] = exp_acc; } exp_acc += (exp_3 - 2); switch(expstr) { case MPEG3_EXP_D45: j = MIN(255, j); dest[j++] = exp_acc; j = MIN(255, j); dest[j++] = exp_acc; case MPEG3_EXP_D25: j = MIN(255, j); dest[j++] = exp_acc; case MPEG3_EXP_D15: j = MIN(255, j); dest[j++] = exp_acc; } } return 0; } int mpeg3audio_ac3_exponent_unpack(mpeg3audio_t *audio, mpeg3_ac3bsi_t *bsi, mpeg3_ac3audblk_t *audblk) { int i, result = 0; for(i = 0; i < bsi->nfchans; i++) result |= mpeg3audio_ac3_exp_unpack_ch(UNPACK_FBW, audblk->chexpstr[i], audblk->nchgrps[i], audblk->exps[i][0], &audblk->exps[i][1], audblk->fbw_exp[i]); if(audblk->cplinu && !result) result |= mpeg3audio_ac3_exp_unpack_ch(UNPACK_CPL, audblk->cplexpstr, audblk->ncplgrps, audblk->cplabsexp << 1, audblk->cplexps, &audblk->cpl_exp[audblk->cplstrtmant]); if(bsi->lfeon && !result) result |= mpeg3audio_ac3_exp_unpack_ch(UNPACK_LFE, audblk->lfeexpstr, 2, audblk->lfeexps[0], &audblk->lfeexps[1], audblk->lfe_exp); return result; } libmpeg3-1.5.4/audio/header.c0000644000175000017500000000014207742725645016153 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include "tables.h" #include libmpeg3-1.5.4/audio/huffman.c0000644000175000017500000003733407742725645016364 0ustar enderender00000000000000#include "huffman.h" /* * huffman tables ... recalcualted to work with my optimzed * decoder scheme (MH) * * probably we could save a few bytes of memory, because the * smaller tables are often the part of a bigger table */ short mpeg3_tab0[] = { 0 }; short mpeg3_tab1[] = { -5, -3, -1, 17, 1, 16, 0 }; short mpeg3_tab2[] = { -15, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 17, -1, 1, 16, 0 }; short mpeg3_tab3[] = { -13, -11, -9, -5, -3, -1, 34, 2, 18, -1, 33, 32, 16, 17, -1, 1, 0 }; short mpeg3_tab5[] = { -29, -25, -23, -15, -7, -5, -3, -1, 51, 35, 50, 49, -3, -1, 19, 3, -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, 17, -1, 1, 16, 0 }; short mpeg3_tab6[] = { -25, -19, -13, -9, -5, -3, -1, 51, 3, 35, -1, 50, 48, -1, 19, 49, -3, -1, 34, 2, 18, -3, -1, 33, 32, 1, -1, 17, -1, 16, 0 }; short mpeg3_tab7[] = { -69, -65, -57, -39, -29, -17, -11, -7, -3, -1, 85, 69, -1, 84, 83, -1, 53, 68, -3, -1, 37, 82, 21, -5, -1, 81, -1, 5, 52, -1, 80, -1, 67, 51, -5, -3, -1, 36, 66, 20, -1, 65, 64, -11, -7, -3, -1, 4, 35, -1, 50, 3, -1, 19, 49, -3, -1, 48, 34, 18, -5, -1, 33, -1, 2, 32, 17, -1, 1, 16, 0 }; short mpeg3_tab8[] = { -65, -63, -59, -45, -31, -19, -13, -7, -5, -3, -1, 85, 84, 69, 83, -3, -1, 53, 68, 37, -3, -1, 82, 5, 21, -5, -1, 81, -1, 52, 67, -3, -1, 80, 51, 36, -5, -3, -1, 66, 20, 65, -3, -1, 4, 64, -1, 35, 50, -9, -7, -3, -1, 19, 49, -1, 3, 48, 34, -1, 2, 32, -1, 18, 33, 17, -3, -1, 1, 16, 0 }; short mpeg3_tab9[] = { -63, -53, -41, -29, -19, -11, -5, -3, -1, 85, 69, 53, -1, 83, -1, 84, 5, -3, -1, 68, 37, -1, 82, 21, -3, -1, 81, 52, -1, 67, -1, 80, 4, -7, -3, -1, 36, 66, -1, 51, 64, -1, 20, 65, -5, -3, -1, 35, 50, 19, -1, 49, -1, 3, 48, -5, -3, -1, 34, 2, 18, -1, 33, 32, -3, -1, 17, 1, -1, 16, 0 }; short mpeg3_tab10[] = { -125,-121,-111, -83, -55, -35, -21, -13, -7, -3, -1, 119, 103, -1, 118, 87, -3, -1, 117, 102, 71, -3, -1, 116, 86, -1, 101, 55, -9, -3, -1, 115, 70, -3, -1, 85, 84, 99, -1, 39, 114, -11, -5, -3, -1, 100, 7, 112, -1, 98, -1, 69, 53, -5, -1, 6, -1, 83, 68, 23, -17, -5, -1, 113, -1, 54, 38, -5, -3, -1, 37, 82, 21, -1, 81, -1, 52, 67, -3, -1, 22, 97, -1, 96, -1, 5, 80, -19, -11, -7, -3, -1, 36, 66, -1, 51, 4, -1, 20, 65, -3, -1, 64, 35, -1, 50, 3, -3, -1, 19, 49, -1, 48, 34, -7, -3, -1, 18, 33, -1, 2, 32, 17, -1, 1, 16, 0 }; short mpeg3_tab11[] = { -121,-113, -89, -59, -43, -27, -17, -7, -3, -1, 119, 103, -1, 118, 117, -3, -1, 102, 71, -1, 116, -1, 87, 85, -5, -3, -1, 86, 101, 55, -1, 115, 70, -9, -7, -3, -1, 69, 84, -1, 53, 83, 39, -1, 114, -1, 100, 7, -5, -1, 113, -1, 23, 112, -3, -1, 54, 99, -1, 96, -1, 68, 37, -13, -7, -5, -3, -1, 82, 5, 21, 98, -3, -1, 38, 6, 22, -5, -1, 97, -1, 81, 52, -5, -1, 80, -1, 67, 51, -1, 36, 66, -15, -11, -7, -3, -1, 20, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -5, -3, -1, 3, 48, 34, 33, -5, -1, 18, -1, 2, 32, 17, -3, -1, 1, 16, 0 }; short mpeg3_tab12[] = { -115, -99, -73, -45, -27, -17, -9, -5, -3, -1, 119, 103, 118, -1, 87, 117, -3, -1, 102, 71, -1, 116, 101, -3, -1, 86, 55, -3, -1, 115, 85, 39, -7, -3, -1, 114, 70, -1, 100, 23, -5, -1, 113, -1, 7, 112, -1, 54, 99, -13, -9, -3, -1, 69, 84, -1, 68, -1, 6, 5, -1, 38, 98, -5, -1, 97, -1, 22, 96, -3, -1, 53, 83, -1, 37, 82, -17, -7, -3, -1, 21, 81, -1, 52, 67, -5, -3, -1, 80, 4, 36, -1, 66, 20, -3, -1, 51, 65, -1, 35, 50, -11, -7, -5, -3, -1, 64, 3, 48, 19, -1, 49, 34, -1, 18, 33, -7, -5, -3, -1, 2, 32, 0, 17, -1, 1, 16 }; short mpeg3_tab13[] = { -509,-503,-475,-405,-333,-265,-205,-153,-115, -83, -53, -35, -21, -13, -9, -7, -5, -3, -1, 254, 252, 253, 237, 255, -1, 239, 223, -3, -1, 238, 207, -1, 222, 191, -9, -3, -1, 251, 206, -1, 220, -1, 175, 233, -1, 236, 221, -9, -5, -3, -1, 250, 205, 190, -1, 235, 159, -3, -1, 249, 234, -1, 189, 219, -17, -9, -3, -1, 143, 248, -1, 204, -1, 174, 158, -5, -1, 142, -1, 127, 126, 247, -5, -1, 218, -1, 173, 188, -3, -1, 203, 246, 111, -15, -7, -3, -1, 232, 95, -1, 157, 217, -3, -1, 245, 231, -1, 172, 187, -9, -3, -1, 79, 244, -3, -1, 202, 230, 243, -1, 63, -1, 141, 216, -21, -9, -3, -1, 47, 242, -3, -1, 110, 156, 15, -5, -3, -1, 201, 94, 171, -3, -1, 125, 215, 78, -11, -5, -3, -1, 200, 214, 62, -1, 185, -1, 155, 170, -1, 31, 241, -23, -13, -5, -1, 240, -1, 186, 229, -3, -1, 228, 140, -1, 109, 227, -5, -1, 226, -1, 46, 14, -1, 30, 225, -15, -7, -3, -1, 224, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -7, -3, -1, 212, 154, -1, 169, 108, -1, 198, 61, -37, -21, -9, -5, -3, -1, 211, 123, 45, -1, 210, 29, -5, -1, 183, -1, 92, 197, -3, -1, 153, 122, 195, -7, -5, -3, -1, 167, 151, 75, 209, -3, -1, 13, 208, -1, 138, 168, -11, -7, -3, -1, 76, 196, -1, 107, 182, -1, 60, 44, -3, -1, 194, 91, -3, -1, 181, 137, 28, -43, -23, -11, -5, -1, 193, -1, 152, 12, -1, 192, -1, 180, 106, -5, -3, -1, 166, 121, 59, -1, 179, -1, 136, 90, -11, -5, -1, 43, -1, 165, 105, -1, 164, -1, 120, 135, -5, -1, 148, -1, 119, 118, 178, -11, -3, -1, 27, 177, -3, -1, 11, 176, -1, 150, 74, -7, -3, -1, 58, 163, -1, 89, 149, -1, 42, 162, -47, -23, -9, -3, -1, 26, 161, -3, -1, 10, 104, 160, -5, -3, -1, 134, 73, 147, -3, -1, 57, 88, -1, 133, 103, -9, -3, -1, 41, 146, -3, -1, 87, 117, 56, -5, -1, 131, -1, 102, 71, -3, -1, 116, 86, -1, 101, 115, -11, -3, -1, 25, 145, -3, -1, 9, 144, -1, 72, 132, -7, -5, -1, 114, -1, 70, 100, 40, -1, 130, 24, -41, -27, -11, -5, -3, -1, 55, 39, 23, -1, 113, -1, 85, 7, -7, -3, -1, 112, 54, -1, 99, 69, -3, -1, 84, 38, -1, 98, 53, -5, -1, 129, -1, 8, 128, -3, -1, 22, 97, -1, 6, 96, -13, -9, -5, -3, -1, 83, 68, 37, -1, 82, 5, -1, 21, 81, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -19, -11, -5, -1, 65, -1, 4, 64, -3, -1, 35, 50, 19, -3, -1, 49, 3, -1, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; short mpeg3_tab15[] = { -495,-445,-355,-263,-183,-115, -77, -43, -27, -13, -7, -3, -1, 255, 239, -1, 254, 223, -1, 238, -1, 253, 207, -7, -3, -1, 252, 222, -1, 237, 191, -1, 251, -1, 206, 236, -7, -3, -1, 221, 175, -1, 250, 190, -3, -1, 235, 205, -1, 220, 159, -15, -7, -3, -1, 249, 234, -1, 189, 219, -3, -1, 143, 248, -1, 204, 158, -7, -3, -1, 233, 127, -1, 247, 173, -3, -1, 218, 188, -1, 111, -1, 174, 15, -19, -11, -3, -1, 203, 246, -3, -1, 142, 232, -1, 95, 157, -3, -1, 245, 126, -1, 231, 172, -9, -3, -1, 202, 187, -3, -1, 217, 141, 79, -3, -1, 244, 63, -1, 243, 216, -33, -17, -9, -3, -1, 230, 47, -1, 242, -1, 110, 240, -3, -1, 31, 241, -1, 156, 201, -7, -3, -1, 94, 171, -1, 186, 229, -3, -1, 125, 215, -1, 78, 228, -15, -7, -3, -1, 140, 200, -1, 62, 109, -3, -1, 214, 227, -1, 155, 185, -7, -3, -1, 46, 170, -1, 226, 30, -5, -1, 225, -1, 14, 224, -1, 93, 213, -45, -25, -13, -7, -3, -1, 124, 199, -1, 77, 139, -1, 212, -1, 184, 154, -7, -3, -1, 169, 108, -1, 198, 61, -1, 211, 210, -9, -5, -3, -1, 45, 13, 29, -1, 123, 183, -5, -1, 209, -1, 92, 208, -1, 197, 138, -17, -7, -3, -1, 168, 76, -1, 196, 107, -5, -1, 182, -1, 153, 12, -1, 60, 195, -9, -3, -1, 122, 167, -1, 166, -1, 192, 11, -1, 194, -1, 44, 91, -55, -29, -15, -7, -3, -1, 181, 28, -1, 137, 152, -3, -1, 193, 75, -1, 180, 106, -5, -3, -1, 59, 121, 179, -3, -1, 151, 136, -1, 43, 90, -11, -5, -1, 178, -1, 165, 27, -1, 177, -1, 176, 105, -7, -3, -1, 150, 74, -1, 164, 120, -3, -1, 135, 58, 163, -17, -7, -3, -1, 89, 149, -1, 42, 162, -3, -1, 26, 161, -3, -1, 10, 160, 104, -7, -3, -1, 134, 73, -1, 148, 57, -5, -1, 147, -1, 119, 9, -1, 88, 133, -53, -29, -13, -7, -3, -1, 41, 103, -1, 118, 146, -1, 145, -1, 25, 144, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 71, -7, -3, -1, 40, 130, -1, 24, 129, -7, -3, -1, 116, 8, -1, 128, 86, -3, -1, 101, 55, -1, 115, 70, -17, -7, -3, -1, 39, 114, -1, 100, 23, -3, -1, 85, 113, -3, -1, 7, 112, 54, -7, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -3, -1, 6, 96, 53, -33, -19, -9, -5, -1, 97, -1, 83, 68, -1, 37, 82, -3, -1, 21, 81, -3, -1, 5, 80, 52, -7, -3, -1, 67, 36, -1, 66, 51, -1, 65, -1, 20, 4, -9, -3, -1, 35, 50, -3, -1, 64, 3, 19, -3, -1, 49, 48, 34, -9, -7, -3, -1, 18, 33, -1, 2, 32, 17, -3, -1, 1, 16, 0 }; short mpeg3_tab16[] = { -509,-503,-461,-323,-103, -37, -27, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 175, -1, 250, 159, -3, -1, 249, 248, 143, -7, -3, -1, 127, 247, -1, 111, 246, 255, -9, -5, -3, -1, 95, 245, 79, -1, 244, 243, -53, -1, 240, -1, 63, -29, -19, -13, -7, -5, -1, 206, -1, 236, 221, 222, -1, 233, -1, 234, 217, -1, 238, -1, 237, 235, -3, -1, 190, 205, -3, -1, 220, 219, 174, -11, -5, -1, 204, -1, 173, 218, -3, -1, 126, 172, 202, -5, -3, -1, 201, 125, 94, 189, 242, -93, -5, -3, -1, 47, 15, 31, -1, 241, -49, -25, -13, -5, -1, 158, -1, 188, 203, -3, -1, 142, 232, -1, 157, 231, -7, -3, -1, 187, 141, -1, 216, 110, -1, 230, 156, -13, -7, -3, -1, 171, 186, -1, 229, 215, -1, 78, -1, 228, 140, -3, -1, 200, 62, -1, 109, -1, 214, 155, -19, -11, -5, -3, -1, 185, 170, 225, -1, 212, -1, 184, 169, -5, -1, 123, -1, 183, 208, 227, -7, -3, -1, 14, 224, -1, 93, 213, -3, -1, 124, 199, -1, 77, 139, -75, -45, -27, -13, -7, -3, -1, 154, 108, -1, 198, 61, -3, -1, 92, 197, 13, -7, -3, -1, 138, 168, -1, 153, 76, -3, -1, 182, 122, 60, -11, -5, -3, -1, 91, 137, 28, -1, 192, -1, 152, 121, -1, 226, -1, 46, 30, -15, -7, -3, -1, 211, 45, -1, 210, 209, -5, -1, 59, -1, 151, 136, 29, -7, -3, -1, 196, 107, -1, 195, 167, -1, 44, -1, 194, 181, -23, -13, -7, -3, -1, 193, 12, -1, 75, 180, -3, -1, 106, 166, 179, -5, -3, -1, 90, 165, 43, -1, 178, 27, -13, -5, -1, 177, -1, 11, 176, -3, -1, 105, 150, -1, 74, 164, -5, -3, -1, 120, 135, 163, -3, -1, 58, 89, 42, -97, -57, -33, -19, -11, -5, -3, -1, 149, 104, 161, -3, -1, 134, 119, 148, -5, -3, -1, 73, 87, 103, 162, -5, -1, 26, -1, 10, 160, -3, -1, 57, 147, -1, 88, 133, -9, -3, -1, 41, 146, -3, -1, 118, 9, 25, -5, -1, 145, -1, 144, 72, -3, -1, 132, 117, -1, 56, 131, -21, -11, -5, -3, -1, 102, 40, 130, -3, -1, 71, 116, 24, -3, -1, 129, 128, -3, -1, 8, 86, 55, -9, -5, -1, 115, -1, 101, 70, -1, 39, 114, -5, -3, -1, 100, 85, 7, 23, -23, -13, -5, -1, 113, -1, 112, 54, -3, -1, 99, 69, -1, 84, 38, -3, -1, 98, 22, -1, 97, -1, 6, 96, -9, -5, -1, 83, -1, 53, 68, -1, 37, 82, -1, 81, -1, 21, 5, -33, -23, -13, -7, -3, -1, 52, 67, -1, 80, 36, -3, -1, 66, 51, 20, -5, -1, 65, -1, 4, 64, -1, 35, 50, -3, -1, 19, 49, -3, -1, 3, 48, 34, -3, -1, 18, 33, -1, 2, 32, -3, -1, 17, 1, 16, 0 }; short mpeg3_tab24[] = { -451,-117, -43, -25, -15, -7, -3, -1, 239, 254, -1, 223, 253, -3, -1, 207, 252, -1, 191, 251, -5, -1, 250, -1, 175, 159, -1, 249, 248, -9, -5, -3, -1, 143, 127, 247, -1, 111, 246, -3, -1, 95, 245, -1, 79, 244, -71, -7, -3, -1, 63, 243, -1, 47, 242, -5, -1, 241, -1, 31, 240, -25, -9, -1, 15, -3, -1, 238, 222, -1, 237, 206, -7, -3, -1, 236, 221, -1, 190, 235, -3, -1, 205, 220, -1, 174, 234, -15, -7, -3, -1, 189, 219, -1, 204, 158, -3, -1, 233, 173, -1, 218, 188, -7, -3, -1, 203, 142, -1, 232, 157, -3, -1, 217, 126, -1, 231, 172, 255,-235, -143, -77, -45, -25, -15, -7, -3, -1, 202, 187, -1, 141, 216, -5, -3, -1, 14, 224, 13, 230, -5, -3, -1, 110, 156, 201, -1, 94, 186, -9, -5, -1, 229, -1, 171, 125, -1, 215, 228, -3, -1, 140, 200, -3, -1, 78, 46, 62, -15, -7, -3, -1, 109, 214, -1, 227, 155, -3, -1, 185, 170, -1, 226, 30, -7, -3, -1, 225, 93, -1, 213, 124, -3, -1, 199, 77, -1, 139, 184, -31, -15, -7, -3, -1, 212, 154, -1, 169, 108, -3, -1, 198, 61, -1, 211, 45, -7, -3, -1, 210, 29, -1, 123, 183, -3, -1, 209, 92, -1, 197, 138, -17, -7, -3, -1, 168, 153, -1, 76, 196, -3, -1, 107, 182, -3, -1, 208, 12, 60, -7, -3, -1, 195, 122, -1, 167, 44, -3, -1, 194, 91, -1, 181, 28, -57, -35, -19, -7, -3, -1, 137, 152, -1, 193, 75, -5, -3, -1, 192, 11, 59, -3, -1, 176, 10, 26, -5, -1, 180, -1, 106, 166, -3, -1, 121, 151, -3, -1, 160, 9, 144, -9, -3, -1, 179, 136, -3, -1, 43, 90, 178, -7, -3, -1, 165, 27, -1, 177, 105, -1, 150, 164, -17, -9, -5, -3, -1, 74, 120, 135, -1, 58, 163, -3, -1, 89, 149, -1, 42, 162, -7, -3, -1, 161, 104, -1, 134, 119, -3, -1, 73, 148, -1, 57, 147, -63, -31, -15, -7, -3, -1, 88, 133, -1, 41, 103, -3, -1, 118, 146, -1, 25, 145, -7, -3, -1, 72, 132, -1, 87, 117, -3, -1, 56, 131, -1, 102, 40, -17, -7, -3, -1, 130, 24, -1, 71, 116, -5, -1, 129, -1, 8, 128, -1, 86, 101, -7, -5, -1, 23, -1, 7, 112, 115, -3, -1, 55, 39, 114, -15, -7, -3, -1, 70, 100, -1, 85, 113, -3, -1, 54, 99, -1, 69, 84, -7, -3, -1, 38, 98, -1, 22, 97, -5, -3, -1, 6, 96, 53, -1, 83, 68, -51, -37, -23, -15, -9, -3, -1, 37, 82, -1, 21, -1, 5, 80, -1, 81, -1, 52, 67, -3, -1, 36, 66, -1, 51, 20, -9, -5, -1, 65, -1, 4, 64, -1, 35, 50, -1, 19, 49, -7, -5, -3, -1, 3, 48, 34, 18, -1, 33, -1, 2, 32, -3, -1, 17, 1, -1, 16, 0 }; short mpeg3_tab_c0[] = { -29, -21, -13, -7, -3, -1, 11, 15, -1, 13, 14, -3, -1, 7, 5, 9, -3, -1, 6, 3, -1, 10, 12, -3, -1, 2, 1, -1, 4, 8, 0 }; short mpeg3_tab_c1[] = { -15, -7, -3, -1, 15, 14, -1, 13, 12, -3, -1, 11, 10, -1, 9, 8, -7, -3, -1, 7, 6, -1, 5, 4, -3, -1, 3, 2, -1, 1, 0 }; struct newhuff mpeg3_ht[] = { { /* 0 */ 0 , mpeg3_tab0 } , { /* 2 */ 0 , mpeg3_tab1 } , { /* 3 */ 0 , mpeg3_tab2 } , { /* 3 */ 0 , mpeg3_tab3 } , { /* 0 */ 0 , mpeg3_tab0 } , { /* 4 */ 0 , mpeg3_tab5 } , { /* 4 */ 0 , mpeg3_tab6 } , { /* 6 */ 0 , mpeg3_tab7 } , { /* 6 */ 0 , mpeg3_tab8 } , { /* 6 */ 0 , mpeg3_tab9 } , { /* 8 */ 0 , mpeg3_tab10 } , { /* 8 */ 0 , mpeg3_tab11 } , { /* 8 */ 0 , mpeg3_tab12 } , { /* 16 */ 0 , mpeg3_tab13 } , { /* 0 */ 0 , mpeg3_tab0 } , { /* 16 */ 0 , mpeg3_tab15 } , { /* 16 */ 1 , mpeg3_tab16 } , { /* 16 */ 2 , mpeg3_tab16 } , { /* 16 */ 3 , mpeg3_tab16 } , { /* 16 */ 4 , mpeg3_tab16 } , { /* 16 */ 6 , mpeg3_tab16 } , { /* 16 */ 8 , mpeg3_tab16 } , { /* 16 */ 10, mpeg3_tab16 } , { /* 16 */ 13, mpeg3_tab16 } , { /* 16 */ 4 , mpeg3_tab24 } , { /* 16 */ 5 , mpeg3_tab24 } , { /* 16 */ 6 , mpeg3_tab24 } , { /* 16 */ 7 , mpeg3_tab24 } , { /* 16 */ 8 , mpeg3_tab24 } , { /* 16 */ 9 , mpeg3_tab24 } , { /* 16 */ 11, mpeg3_tab24 } , { /* 16 */ 13, mpeg3_tab24 } }; struct newhuff mpeg3_htc[] = { { /* 1 , 1 , */ 0 , mpeg3_tab_c0 } , { /* 1 , 1 , */ 0 , mpeg3_tab_c1 } }; libmpeg3-1.5.4/audio/huffman.h0000644000175000017500000000166707742725645016371 0ustar enderender00000000000000#ifndef HUFFMAN_H #define HUFFMAN_H /* * huffman tables ... recalcualted to work with my optimzed * decoder scheme (MH) * * probably we could save a few bytes of memory, because the * smaller tables are often the part of a bigger table */ struct newhuff { unsigned int linbits; short *table; }; extern short mpeg3_tab0[1]; extern short mpeg3_tab1[7]; extern short mpeg3_tab2[17]; extern short mpeg3_tab3[17]; extern short mpeg3_tab5[31]; extern short mpeg3_tab6[31]; extern short mpeg3_tab7[71]; extern short mpeg3_tab8[71]; extern short mpeg3_tab9[71]; extern short mpeg3_tab10[127]; extern short mpeg3_tab11[127]; extern short mpeg3_tab12[127]; extern short mpeg3_tab13[511]; extern short mpeg3_tab15[511]; extern short mpeg3_tab16[511]; extern short mpeg3_tab24[511]; extern short mpeg3_tab_c0[31]; extern short mpeg3_tab_c1[31]; extern struct newhuff mpeg3_ht[32]; extern struct newhuff mpeg3_htc[2]; #endif libmpeg3-1.5.4/audio/layer1.c0000644000175000017500000000011507742725645016120 0ustar enderender00000000000000#include "mpeg3audio.h" int mpeg3audio_dolayer1(mpeg3audio_t *audio) { ; } libmpeg3-1.5.4/audio/layer2.c0000644000175000017500000004123207770675460016126 0ustar enderender00000000000000/* * most other tables are calculated on program start (which is (of course) * not ISO-conform) .. * Layer-3 huffman table is in huffman.h */ #include "mpeg3private.h" #include "mpeg3protos.h" #include "tables.h" static struct al_table alloc_0[] = { {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511}, {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767}, {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511}, {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767}, {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511}, {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767} }; static struct al_table alloc_1[] = { {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511}, {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767}, {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511}, {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767}, {4,0},{5,3},{3,-3},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255},{10,-511}, {11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {3,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767}, {2,0},{5,3},{7,5},{16,-32767} }; static struct al_table alloc_2[] = { {4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255}, {10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383}, {4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255}, {10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63} }; static struct al_table alloc_3[] = { {4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255}, {10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383}, {4,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127},{9,-255}, {10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191},{15,-16383}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63} }; static struct al_table alloc_4[] = { {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191}, {4,0},{5,3},{7,5},{3,-3},{10,9},{4,-7},{5,-15},{6,-31},{7,-63},{8,-127}, {9,-255},{10,-511},{11,-1023},{12,-2047},{13,-4095},{14,-8191}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {3,0},{5,3},{7,5},{10,9},{4,-7},{5,-15},{6,-31},{7,-63}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9}, {2,0},{5,3},{7,5},{10,9} }; static int select_table(mpeg3_layer_t *audio) { static int translate[3][2][16] = {{{ 0,2,2,2,2,2,2,0,0,0,1,1,1,1,1,0}, { 0,2,2,0,0,0,1,1,1,1,1,1,1,1,1,0}}, {{ 0,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0}, { 0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0}}, {{ 0,3,3,3,3,3,3,0,0,0,1,1,1,1,1,0}, { 0,3,3,0,0,0,1,1,1,1,1,1,1,1,1,0}}}; int table, sblim; static struct al_table *tables[5] = {alloc_0, alloc_1, alloc_2, alloc_3, alloc_4}; static int sblims[5] = {27, 30, 8, 12, 30}; if(audio->lsf) table = 4; else table = translate[audio->sampling_frequency_code][2 - audio->channels][audio->bitrate_index]; sblim = sblims[table]; audio->alloc = tables[table]; audio->II_sblimit = sblim; return 0; } static int step_one(mpeg3_layer_t *audio, unsigned int *bit_alloc, int *scale) { int stereo = audio->channels - 1; int sblimit = audio->II_sblimit; int jsbound = audio->jsbound; int sblimit2 = audio->II_sblimit << stereo; struct al_table *alloc1 = audio->alloc; int i, result = 0; unsigned int *scfsi_buf = audio->layer2_scfsi_buf; unsigned int *scfsi, *bita; int sc, step; bita = bit_alloc; if(stereo) { /* Stereo */ for(i = jsbound;i ; i--, alloc1 += (1 << step)) { *bita++ = (char)mpeg3bits_getbits(audio->stream, step = alloc1->bits); *bita++ = (char)mpeg3bits_getbits(audio->stream, step); } for(i = sblimit-jsbound; i; i--, alloc1 += (1 << step)) { bita[0] = (char)mpeg3bits_getbits(audio->stream, step = alloc1->bits); bita[1] = bita[0]; bita += 2; } bita = bit_alloc; scfsi = scfsi_buf; for(i = sblimit2; i; i--) if(*bita++) *scfsi++ = (char)mpeg3bits_getbits(audio->stream, 2); } else { /* mono */ for(i = sblimit; i; i--, alloc1 += (1 << step)) *bita++ = (char)mpeg3bits_getbits(audio->stream, step = alloc1->bits); bita = bit_alloc; scfsi = scfsi_buf; for(i = sblimit; i; i--) if (*bita++) *scfsi++ = (char)mpeg3bits_getbits(audio->stream, 2); } bita = bit_alloc; scfsi = scfsi_buf; for(i = sblimit2; i; i--) { if(*bita++) switch(*scfsi++) { case 0: *scale++ = mpeg3bits_getbits(audio->stream, 6); *scale++ = mpeg3bits_getbits(audio->stream, 6); *scale++ = mpeg3bits_getbits(audio->stream, 6); break; case 1 : *scale++ = sc = mpeg3bits_getbits(audio->stream, 6); *scale++ = sc; *scale++ = mpeg3bits_getbits(audio->stream, 6); break; case 2: *scale++ = sc = mpeg3bits_getbits(audio->stream, 6); *scale++ = sc; *scale++ = sc; break; default: /* case 3 */ *scale++ = mpeg3bits_getbits(audio->stream, 6); *scale++ = sc = mpeg3bits_getbits(audio->stream, 6); *scale++ = sc; break; } } return result; } static int step_two(mpeg3_layer_t *audio, unsigned int *bit_alloc, float fraction[2][4][SBLIMIT], int *scale, int x1) { int i, j, k, ba, result = 0; int channels = audio->channels; int sblimit = audio->II_sblimit; int jsbound = audio->jsbound; struct al_table *alloc2, *alloc1 = audio->alloc; unsigned int *bita = bit_alloc; int d1, step, test; for(i = 0; i < jsbound; i++, alloc1 += (1 << step)) { step = alloc1->bits; for(j = 0; j < channels; j++) { if(ba = *bita++) { k = (alloc2 = alloc1 + ba)->bits; if((d1 = alloc2->d) < 0) { float cm = mpeg3_muls[k][scale[x1]]; fraction[j][0][i] = ((float)((int)mpeg3bits_getbits(audio->stream, k) + d1)) * cm; fraction[j][1][i] = ((float)((int)mpeg3bits_getbits(audio->stream, k) + d1)) * cm; fraction[j][2][i] = ((float)((int)mpeg3bits_getbits(audio->stream, k) + d1)) * cm; } else { static int *table[] = {0, 0, 0, mpeg3_grp_3tab, 0, mpeg3_grp_5tab, 0, 0, 0, mpeg3_grp_9tab}; unsigned int idx, *tab, m = scale[x1]; idx = (unsigned int)mpeg3bits_getbits(audio->stream, k); tab = (unsigned int*)(table[d1] + idx + idx + idx); fraction[j][0][i] = mpeg3_muls[*tab++][m]; fraction[j][1][i] = mpeg3_muls[*tab++][m]; fraction[j][2][i] = mpeg3_muls[*tab][m]; } scale += 3; } else fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0; } } for(i = jsbound; i < sblimit; i++, alloc1 += (1 << step)) { step = alloc1->bits; /* channel 1 and channel 2 bitalloc are the same */ bita++; if((ba = *bita++)) { k=(alloc2 = alloc1+ba)->bits; if((d1 = alloc2->d) < 0) { float cm; cm = mpeg3_muls[k][scale[x1 + 3]]; fraction[1][0][i] = (fraction[0][0][i] = (float)((int)mpeg3bits_getbits(audio->stream, k) + d1)) * cm; fraction[1][1][i] = (fraction[0][1][i] = (float)((int)mpeg3bits_getbits(audio->stream, k) + d1)) * cm; fraction[1][2][i] = (fraction[0][2][i] = (float)((int)mpeg3bits_getbits(audio->stream, k) + d1)) * cm; cm = mpeg3_muls[k][scale[x1]]; fraction[0][0][i] *= cm; fraction[0][1][i] *= cm; fraction[0][2][i] *= cm; } else { static int *table[] = {0, 0, 0, mpeg3_grp_3tab, 0, mpeg3_grp_5tab, 0, 0, 0, mpeg3_grp_9tab}; unsigned int idx, *tab, m1, m2; m1 = scale[x1]; m2 = scale[x1+3]; idx = (unsigned int)mpeg3bits_getbits(audio->stream, k); tab = (unsigned int*)(table[d1] + idx + idx + idx); fraction[0][0][i] = mpeg3_muls[*tab][m1]; fraction[1][0][i] = mpeg3_muls[*tab++][m2]; fraction[0][1][i] = mpeg3_muls[*tab][m1]; fraction[1][1][i] = mpeg3_muls[*tab++][m2]; fraction[0][2][i] = mpeg3_muls[*tab][m1]; fraction[1][2][i] = mpeg3_muls[*tab][m2]; } scale += 6; } else { fraction[0][0][i] = fraction[0][1][i] = fraction[0][2][i] = fraction[1][0][i] = fraction[1][1][i] = fraction[1][2][i] = 0.0; } /* should we use individual scalefac for channel 2 or is the current way the right one , where we just copy channel 1 to channel 2 ?? The current 'strange' thing is, that we throw away the scalefac values for the second channel ...!! -> changed .. now we use the scalefac values of channel one !! */ } if(sblimit > SBLIMIT) sblimit = SBLIMIT; for(i = sblimit; i < SBLIMIT; i++) for(j = 0; j < channels; j++) fraction[j][0][i] = fraction[j][1][i] = fraction[j][2][i] = 0.0; return result; } int mpeg3audio_dolayer2(mpeg3_layer_t *audio, char *frame, int frame_size, float **output, int render) { int i, j, result = 0; int channels = audio->channels; float fraction[2][4][SBLIMIT]; /* pick_table clears unused subbands */ unsigned int bit_alloc[64]; int scale[192]; int single = audio->single; int output_position = 0; frame += 4; /* Set up bitstream to use buffer */ mpeg3bits_use_ptr(audio->stream, frame); if(audio->error_protection) mpeg3bits_getbits(audio->stream, 16); select_table(audio); audio->jsbound = (audio->mode == MPG_MD_JOINT_STEREO) ? (audio->mode_ext << 2) + 4 : audio->II_sblimit; if(channels == 1 || single == 3) single = 0; result |= step_one(audio, bit_alloc, scale); for(i = 0; i < SCALE_BLOCK && !result; i++) { result |= step_two(audio, bit_alloc, fraction, scale, i >> 2); for(j = 0; j < 3; j++) { if(single >= 0) { /* Monaural */ if(render) mpeg3audio_synth_stereo(audio, fraction[0][j], 0, output[0], &(output_position)); else output_position += 32; } else { /* Stereo */ int p1 = output_position; if(render) { //printf(__FUNCTION__ " 3\n"); mpeg3audio_synth_stereo(audio, fraction[0][j], 0, output[0], &p1); //printf(__FUNCTION__ " 4\n"); mpeg3audio_synth_stereo(audio, fraction[1][j], 1, output[1], &(output_position)); //printf(__FUNCTION__ " 5\n"); } else output_position += 32; } } } return output_position; } libmpeg3-1.5.4/audio/layer3.c0000644000175000017500000010612207767526350016126 0ustar enderender00000000000000#include "huffman.h" #include "mpeg3private.h" #include "mpeg3protos.h" #include "tables.h" #include #include struct gr_info_s { int scfsi; unsigned part2_3_length; unsigned big_values; unsigned scalefac_compress; unsigned block_type; unsigned mixed_block_flag; unsigned table_select[3]; unsigned subblock_gain[3]; unsigned maxband[3]; unsigned maxbandl; unsigned maxb; unsigned region1start; unsigned region2start; unsigned preflag; unsigned scalefac_scale; unsigned count1table_select; float *full_gain[3]; float *pow2gain; }; struct sideinfo_s { unsigned main_data_begin; unsigned private_bits; struct { struct gr_info_s gr[2]; } ch[2]; }; static int get_scale_factors_1(mpeg3_layer_t *audio, int *scf, struct gr_info_s *gr_info, int ch, int gr) { static unsigned char slen[2][16] = {{0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4}, {0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3}}; int numbits; int num0 = slen[0][gr_info->scalefac_compress]; int num1 = slen[1][gr_info->scalefac_compress]; if (gr_info->block_type == 2) { int i = 18; numbits = (num0 + num1) * 18; if (gr_info->mixed_block_flag) { for(i = 8; i; i--) *scf++ = mpeg3bits_getbits(audio->stream, num0); i = 9; /* num0 * 17 + num1 * 18 */ numbits -= num0; } for( ; i; i--) *scf++ = mpeg3bits_getbits(audio->stream, num0); for(i = 18; i; i--) *scf++ = mpeg3bits_getbits(audio->stream, num1); /* short[13][0..2] = 0 */ *scf++ = 0; *scf++ = 0; *scf++ = 0; } else { int i; int scfsi = gr_info->scfsi; if(scfsi < 0) { /* scfsi < 0 => granule == 0 */ for(i = 11; i; i--) { *scf++ = mpeg3bits_getbits(audio->stream, num0); } for(i = 10; i; i--) *scf++ = mpeg3bits_getbits(audio->stream, num1); numbits = (num0 + num1) * 10 + num0; *scf++ = 0; } else { numbits = 0; if(!(scfsi & 0x8)) { for(i = 0; i < 6; i++) { *scf++ = mpeg3bits_getbits(audio->stream, num0); } numbits += num0 * 6; } else { scf += 6; } if(!(scfsi & 0x4)) { for(i = 0; i < 5; i++) *scf++ = mpeg3bits_getbits(audio->stream, num0); numbits += num0 * 5; } else { scf += 5; } if(!(scfsi & 0x2)) { for(i = 0; i < 5; i++) *scf++ = mpeg3bits_getbits(audio->stream, num1); numbits += num1 * 5; } else { scf += 5; } if(!(scfsi & 0x1)) { for(i = 0; i < 5; i++) *scf++ = mpeg3bits_getbits(audio->stream, num1); numbits += num1 * 5; } else { scf += 5; } *scf++ = 0; /* no l[21] in original sources */ } } return numbits; } static int get_scale_factors_2(mpeg3_layer_t *audio, int *scf, struct gr_info_s *gr_info, int i_stereo) { unsigned char *pnt; int i, j, n = 0, numbits = 0; unsigned int slen; static unsigned char stab[3][6][4] = {{{ 6, 5, 5,5 }, { 6, 5, 7,3 }, { 11,10,0,0}, { 7, 7, 7,0 }, { 6, 6, 6,3 }, { 8, 8,5,0}}, {{ 9, 9, 9,9 }, { 9, 9,12,6 }, { 18,18,0,0}, {12,12,12,0 }, {12, 9, 9,6 }, { 15,12,9,0}}, {{ 6, 9, 9,9 }, { 6, 9,12,6 }, { 15,18,0,0}, { 6,15,12,0 }, { 6,12, 9,6 }, { 6,18,9,0}}}; /* i_stereo AND second channel -> do_layer3() checks this */ if(i_stereo) slen = mpeg3_i_slen2[gr_info->scalefac_compress >> 1]; else slen = mpeg3_n_slen2[gr_info->scalefac_compress]; gr_info->preflag = (slen >> 15) & 0x1; n = 0; if(gr_info->block_type == 2 ) { n++; if(gr_info->mixed_block_flag) n++; } pnt = stab[n][(slen >> 12) & 0x7]; for(i = 0; i < 4; i++) { int num = slen & 0x7; slen >>= 3; if(num) { for(j = 0; j < (int)(pnt[i]); j++) *scf++ = mpeg3bits_getbits(audio->stream, num); numbits += pnt[i] * num; } else { for(j = 0; j < (int)(pnt[i]); j++) *scf++ = 0; } } n = (n << 1) + 1; for(i = 0; i < n; i++) *scf++ = 0; return numbits; } static int pretab1[22] = {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,3,3,3,2,0}; static int pretab2[22] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* * Dequantize samples (includes huffman decoding) * * 24 is enough because tab13 has max. a 19 bit huffvector */ #define BITSHIFT ((sizeof(int32_t) - 1) * 8) #define REFRESH_MASK \ while(num < BITSHIFT) \ { \ mask |= mpeg3bits_getbits(audio->stream, 8) << (BITSHIFT - num); \ num += 8; \ part2remain -= 8; \ } static int dequantize_sample(mpeg3_layer_t *audio, float xr[SBLIMIT][SSLIMIT], int *scf, struct gr_info_s *gr_info, int sfreq, int part2bits) { int shift = 1 + gr_info->scalefac_scale; float *xrpnt = (float*)xr; int l[3],l3; int part2remain = gr_info->part2_3_length - part2bits; int *me; int num = mpeg3bits_getbitoffset(audio->stream); int32_t mask = mpeg3bits_getbits(audio->stream, num); //printf("III_dequantize_sample 1 %08x %d\n", mask, num); mask = mask << (BITSHIFT + 8 - num); part2remain -= num; { int bv = gr_info->big_values; int region1 = gr_info->region1start; int region2 = gr_info->region2start; l3 = ((576 >> 1) - bv) >> 1; /* * we may lose the 'odd' bit here !! * check this later again */ if(bv <= region1) { l[0] = bv; l[1] = 0; l[2] = 0; } else { l[0] = region1; if(bv <= region2) { l[1] = bv - l[0]; l[2] = 0; } else { l[1] = region2 - l[0]; l[2] = bv - region2; } } } if(gr_info->block_type == 2) { /* * decoding with short or mixed mode BandIndex table */ int i, max[4]; int step = 0, lwin = 3, cb = 0; register float v = 0.0; register int *m, mc; if(gr_info->mixed_block_flag) { max[3] = -1; max[0] = max[1] = max[2] = 2; m = mpeg3_map[sfreq][0]; me = mpeg3_mapend[sfreq][0]; } else { max[0] = max[1] = max[2] = max[3] = -1; /* max[3] not floatly needed in this case */ m = mpeg3_map[sfreq][1]; me = mpeg3_mapend[sfreq][1]; } mc = 0; for(i = 0; i < 2; i++) { int lp = l[i]; struct newhuff *h = mpeg3_ht + gr_info->table_select[i]; for( ; lp; lp--, mc--) { register int x,y; if(!mc) { mc = *m++; xrpnt = ((float*)xr) + (*m++); lwin = *m++; cb = *m++; if(lwin == 3) { v = gr_info->pow2gain[(*scf++) << shift]; step = 1; } else { v = gr_info->full_gain[lwin][(*scf++) << shift]; step = 3; } } { register short *val = h->table; REFRESH_MASK; while((y = *val++) < 0) { if (mask < 0) val -= y; num--; mask <<= 1; } x = y >> 4; y &= 0xf; } if(x == 15 && h->linbits) { max[lwin] = cb; REFRESH_MASK; x += ((uint32_t)mask) >> (BITSHIFT + 8 - h->linbits); num -= h->linbits + 1; mask <<= h->linbits; if(mask < 0) *xrpnt = -mpeg3_ispow[x] * v; else *xrpnt = mpeg3_ispow[x] * v; mask <<= 1; } else if(x) { max[lwin] = cb; if(mask < 0) *xrpnt = -mpeg3_ispow[x] * v; else *xrpnt = mpeg3_ispow[x] * v; num--; mask <<= 1; } else *xrpnt = 0.0; xrpnt += step; if(y == 15 && h->linbits) { max[lwin] = cb; REFRESH_MASK; y += ((uint32_t) mask) >> (BITSHIFT + 8 - h->linbits); num -= h->linbits + 1; mask <<= h->linbits; if(mask < 0) *xrpnt = -mpeg3_ispow[y] * v; else *xrpnt = mpeg3_ispow[y] * v; mask <<= 1; } else if(y) { max[lwin] = cb; if(mask < 0) *xrpnt = -mpeg3_ispow[y] * v; else *xrpnt = mpeg3_ispow[y] * v; num--; mask <<= 1; } else *xrpnt = 0.0; xrpnt += step; } } for( ;l3 && (part2remain + num > 0); l3--) { struct newhuff *h = mpeg3_htc + gr_info->count1table_select; register short *val = h->table, a; REFRESH_MASK; while((a = *val++) < 0) { if (mask < 0) val -= a; num--; mask <<= 1; } if(part2remain + num <= 0) { num -= part2remain + num; break; } for(i = 0; i < 4; i++) { if(!(i & 1)) { if(!mc) { mc = *m++; xrpnt = ((float*)xr) + (*m++); lwin = *m++; cb = *m++; if(lwin == 3) { v = gr_info->pow2gain[(*scf++) << shift]; step = 1; } else { v = gr_info->full_gain[lwin][(*scf++) << shift]; step = 3; } } mc--; } if((a & (0x8 >> i))) { max[lwin] = cb; if(part2remain + num <= 0) { break; } if(mask < 0) *xrpnt = -v; else *xrpnt = v; num--; mask <<= 1; } else *xrpnt = 0.0; xrpnt += step; } } if(lwin < 3) { /* short band? */ while(1) { for( ;mc > 0; mc--) { /* short band -> step=3 */ *xrpnt = 0.0; xrpnt += 3; *xrpnt = 0.0; xrpnt += 3; } if(m >= me) break; mc = *m++; xrpnt = ((float*)xr) + *m++; /* optimize: field will be set to zero at the end of the function */ if(*m++ == 0) break; /* cb */ m++; } } gr_info->maxband[0] = max[0] + 1; gr_info->maxband[1] = max[1] + 1; gr_info->maxband[2] = max[2] + 1; gr_info->maxbandl = max[3] + 1; { int rmax = max[0] > max[1] ? max[0] : max[1]; rmax = (rmax > max[2] ? rmax : max[2]) + 1; gr_info->maxb = rmax ? mpeg3_shortLimit[sfreq][rmax] : mpeg3_longLimit[sfreq][max[3] + 1]; } } else { /* * decoding with 'long' BandIndex table (block_type != 2) */ int *pretab = gr_info->preflag ? pretab1 : pretab2; int i, max = -1; int cb = 0; int *m = mpeg3_map[sfreq][2]; register float v = 0.0; int mc = 0; /* * long hash table values */ for(i = 0; i < 3; i++) { int lp = l[i]; struct newhuff *h = mpeg3_ht + gr_info->table_select[i]; for(; lp; lp--, mc--) { int x, y; if(!mc) { mc = *m++; cb = *m++; if(cb == 21) v = 0.0; else v = gr_info->pow2gain[((*scf++) + (*pretab++)) << shift]; } { register short *val = h->table; REFRESH_MASK; while((y = *val++) < 0) { if(mask < 0) val -= y; num--; mask <<= 1; } x = y >> 4; y &= 0xf; } if(x == 15 && h->linbits) { max = cb; REFRESH_MASK; x += ((uint32_t) mask) >> (BITSHIFT + 8 - h->linbits); num -= h->linbits + 1; mask <<= h->linbits; if(mask < 0) *xrpnt++ = -mpeg3_ispow[x] * v; else *xrpnt++ = mpeg3_ispow[x] * v; mask <<= 1; } else if(x) { max = cb; if(mask < 0) *xrpnt++ = -mpeg3_ispow[x] * v; else *xrpnt++ = mpeg3_ispow[x] * v; num--; mask <<= 1; } else *xrpnt++ = 0.0; if(y == 15 && h->linbits) { max = cb; REFRESH_MASK; y += ((uint32_t) mask) >> (BITSHIFT + 8 - h->linbits); num -= h->linbits + 1; mask <<= h->linbits; if(mask < 0) *xrpnt++ = -mpeg3_ispow[y] * v; else *xrpnt++ = mpeg3_ispow[y] * v; mask <<= 1; } else if(y) { max = cb; if(mask < 0) *xrpnt++ = -mpeg3_ispow[y] * v; else *xrpnt++ = mpeg3_ispow[y] * v; num--; mask <<= 1; } else *xrpnt++ = 0.0; } } /* * short (count1table) values */ for( ; l3 && (part2remain + num > 0); l3--) { struct newhuff *h = mpeg3_htc + gr_info->count1table_select; register short *val = h->table, a; REFRESH_MASK; while((a = *val++) < 0) { if(mask < 0) val -= a; num--; mask <<= 1; } if(part2remain + num <= 0) { num -= part2remain + num; break; } for(i = 0; i < 4; i++) { if(!(i & 1)) { if(!mc) { mc = *m++; cb = *m++; if(cb == 21) v = 0.0; else v = gr_info->pow2gain[((*scf++) + (*pretab++)) << shift]; } mc--; } if((a & (0x8 >> i))) { max = cb; if(part2remain + num <= 0) { break; } if(mask < 0) *xrpnt++ = -v; else *xrpnt++ = v; num--; mask <<= 1; } else *xrpnt++ = 0.0; } } gr_info->maxbandl = max + 1; gr_info->maxb = mpeg3_longLimit[sfreq][gr_info->maxbandl]; } part2remain += num; // mpeg3bits_start_reverse(audio->stream); mpeg3bits_getbits_reverse(audio->stream, num); mpeg3bits_start_forward(audio->stream); //printf("III_dequantize_sample 3 %d %04x\n", audio->stream->bit_number, mpeg3bits_showbits(audio->stream, 16)); num = 0; while(xrpnt < &xr[SBLIMIT][0]) *xrpnt++ = 0.0; while(part2remain > 16) { mpeg3bits_getbits(audio->stream, 16); /* Dismiss stuffing Bits */ part2remain -= 16; } if(part2remain > 0) { mpeg3bits_getbits(audio->stream, part2remain); } else if(part2remain < 0) { printf("dequantize_sample: can't rewind stream %d bits! data=%02x%02x%02x%02x\n", -part2remain, (unsigned char)audio->stream->input_ptr[-3], (unsigned char)audio->stream->input_ptr[-2], (unsigned char)audio->stream->input_ptr[-1], (unsigned char)audio->stream->input_ptr[0]); return 1; /* -> error */ } return 0; } static int get_side_info(mpeg3_layer_t *audio, struct sideinfo_s *si, int channels, int ms_stereo, long sfreq, int single, int lsf) { int ch, gr; int powdiff = (single == 3) ? 4 : 0; static const int tabs[2][5] = { { 2,9,5,3,4 } , { 1,8,1,2,9 } }; const int *tab = tabs[lsf]; si->main_data_begin = mpeg3bits_getbits(audio->stream, tab[1]); if(channels == 1) si->private_bits = mpeg3bits_getbits(audio->stream, tab[2]); else si->private_bits = mpeg3bits_getbits(audio->stream, tab[3]); if(!lsf) { for(ch = 0; ch < channels; ch++) { si->ch[ch].gr[0].scfsi = -1; si->ch[ch].gr[1].scfsi = mpeg3bits_getbits(audio->stream, 4); } } for(gr = 0; gr < tab[0]; gr++) { for(ch = 0; ch < channels; ch++) { register struct gr_info_s *gr_info = &(si->ch[ch].gr[gr]); gr_info->part2_3_length = mpeg3bits_getbits(audio->stream, 12); gr_info->big_values = mpeg3bits_getbits(audio->stream, 9); if(gr_info->big_values > 288) { fprintf(stderr,"get_side_info: big_values too large!\n"); gr_info->big_values = 288; } gr_info->pow2gain = mpeg3_gainpow2 + 256 - mpeg3bits_getbits(audio->stream, 8) + powdiff; if(ms_stereo) gr_info->pow2gain += 2; gr_info->scalefac_compress = mpeg3bits_getbits(audio->stream, tab[4]); if(mpeg3bits_getbits(audio->stream, 1)) { /* window switch flag */ int i; gr_info->block_type = mpeg3bits_getbits(audio->stream, 2); gr_info->mixed_block_flag = mpeg3bits_getbits(audio->stream, 1); gr_info->table_select[0] = mpeg3bits_getbits(audio->stream, 5); gr_info->table_select[1] = mpeg3bits_getbits(audio->stream, 5); /* * table_select[2] not needed, because there is no region2, * but to satisfy some verifications tools we set it either. */ gr_info->table_select[2] = 0; for(i = 0; i < 3; i++) gr_info->full_gain[i] = gr_info->pow2gain + (mpeg3bits_getbits(audio->stream, 3) << 3); if(gr_info->block_type == 0) { fprintf(stderr,"Blocktype == 0 and window-switching == 1 not allowed.\n"); return 1; } /* region_count/start parameters are implicit in this case. */ if(!lsf || gr_info->block_type == 2) gr_info->region1start = 36 >> 1; else { /* check this again for 2.5 and sfreq=8 */ if(sfreq == 8) gr_info->region1start = 108 >> 1; else gr_info->region1start = 54 >> 1; } gr_info->region2start = 576 >> 1; } else { int i, r0c, r1c; for(i = 0; i < 3; i++) gr_info->table_select[i] = mpeg3bits_getbits(audio->stream, 5); r0c = mpeg3bits_getbits(audio->stream, 4); r1c = mpeg3bits_getbits(audio->stream, 3); gr_info->region1start = mpeg3_bandInfo[sfreq].longIdx[r0c + 1] >> 1 ; gr_info->region2start = mpeg3_bandInfo[sfreq].longIdx[r0c + 1 + r1c + 1] >> 1; gr_info->block_type = 0; gr_info->mixed_block_flag = 0; } if(!lsf) gr_info->preflag = mpeg3bits_getbits(audio->stream, 1); gr_info->scalefac_scale = mpeg3bits_getbits(audio->stream, 1); gr_info->count1table_select = mpeg3bits_getbits(audio->stream, 1); } } return 0; } static int hybrid(mpeg3_layer_t *audio, float fsIn[SBLIMIT][SSLIMIT], float tsOut[SSLIMIT][SBLIMIT], int ch, struct gr_info_s *gr_info) { float *tspnt = (float *) tsOut; float *rawout1,*rawout2; int bt, sb = 0; { int b = audio->mp3_blc[ch]; rawout1 = audio->mp3_block[b][ch]; b = -b + 1; rawout2 = audio->mp3_block[b][ch]; audio->mp3_blc[ch] = b; } if(gr_info->mixed_block_flag) { sb = 2; mpeg3audio_dct36(fsIn[0], rawout1, rawout2, mpeg3_win[0], tspnt); mpeg3audio_dct36(fsIn[1], rawout1 + 18, rawout2 + 18, mpeg3_win1[0], tspnt + 1); rawout1 += 36; rawout2 += 36; tspnt += 2; } bt = gr_info->block_type; if(bt == 2) { for( ; sb < gr_info->maxb; sb += 2, tspnt += 2, rawout1 += 36, rawout2 += 36) { mpeg3audio_dct12(fsIn[sb] ,rawout1 ,rawout2 ,mpeg3_win[2] ,tspnt); mpeg3audio_dct12(fsIn[sb + 1], rawout1 + 18, rawout2 + 18, mpeg3_win1[2], tspnt + 1); } } else { for( ; sb < gr_info->maxb; sb += 2, tspnt += 2, rawout1 += 36, rawout2 += 36) { mpeg3audio_dct36(fsIn[sb], rawout1, rawout2, mpeg3_win[bt], tspnt); mpeg3audio_dct36(fsIn[sb + 1], rawout1 + 18, rawout2 + 18, mpeg3_win1[bt], tspnt + 1); } } for( ; sb < SBLIMIT; sb++, tspnt++) { int i; for(i = 0; i < SSLIMIT; i++) { tspnt[i * SBLIMIT] = *rawout1++; *rawout2++ = 0.0; } } return 0; } static int antialias(mpeg3_layer_t *audio, float xr[SBLIMIT][SSLIMIT], struct gr_info_s *gr_info) { int sblim; if(gr_info->block_type == 2) { if(!gr_info->mixed_block_flag) return 0; sblim = 1; } else { sblim = gr_info->maxb-1; } /* 31 alias-reduction operations between each pair of sub-bands */ /* with 8 butterflies between each pair */ { int sb; float *xr1 = (float*)xr[1]; for(sb = sblim; sb; sb--, xr1 += 10) { int ss; float *cs, *ca; float *xr2; cs = mpeg3_aa_cs; ca = mpeg3_aa_ca; xr2 = xr1; for(ss = 7; ss >= 0; ss--) { /* upper and lower butterfly inputs */ register float bu, bd; bu = *--xr2; bd = *xr1; *xr2 = (bu * (*cs) ) - (bd * (*ca) ); *xr1++ = (bd * (*cs++) ) + (bu * (*ca++) ); } } } return 0; } /* * III_stereo: calculate float channel values for Joint-I-Stereo-mode */ static int calc_i_stereo(mpeg3_layer_t *audio, float xr_buf[2][SBLIMIT][SSLIMIT], int *scalefac, struct gr_info_s *gr_info, int sfreq, int ms_stereo, int lsf) { float (*xr)[SBLIMIT*SSLIMIT] = (float (*)[SBLIMIT*SSLIMIT] ) xr_buf; struct mpeg3_bandInfoStruct *bi = &mpeg3_bandInfo[sfreq]; const float *tab1, *tab2; int tab; /* TODO: optimize as static */ static const float *tabs[3][2][2] = { { { mpeg3_tan1_1, mpeg3_tan2_1 } , { mpeg3_tan1_2, mpeg3_tan2_2 } }, { { mpeg3_pow1_1[0], mpeg3_pow2_1[0] } , { mpeg3_pow1_2[0], mpeg3_pow2_2[0] } } , { { mpeg3_pow1_1[1], mpeg3_pow2_1[1] } , { mpeg3_pow1_2[1], mpeg3_pow2_2[1] } } }; tab = lsf + (gr_info->scalefac_compress & lsf); tab1 = tabs[tab][ms_stereo][0]; tab2 = tabs[tab][ms_stereo][1]; if(gr_info->block_type == 2) { int lwin,do_l = 0; if(gr_info->mixed_block_flag) do_l = 1; for(lwin = 0; lwin < 3; lwin++) { /* process each window */ /* get first band with zero values */ /* sfb is minimal 3 for mixed mode */ int is_p, sb, idx, sfb = gr_info->maxband[lwin]; if(sfb > 3) do_l = 0; for( ; sfb < 12 ; sfb++) { /* scale: 0-15 */ is_p = scalefac[sfb * 3 + lwin - gr_info->mixed_block_flag]; if(is_p != 7) { float t1, t2; sb = bi->shortDiff[sfb]; idx = bi->shortIdx[sfb] + lwin; t1 = tab1[is_p]; t2 = tab2[is_p]; for( ; sb > 0; sb--, idx += 3) { float v = xr[0][idx]; xr[0][idx] = v * t1; xr[1][idx] = v * t2; } } } /* in the original: copy 10 to 11 , here: copy 11 to 12 maybe still wrong??? (copy 12 to 13?) */ /* scale: 0-15 */ is_p = scalefac[11 * 3 + lwin - gr_info->mixed_block_flag]; sb = bi->shortDiff[12]; idx = bi->shortIdx[12] + lwin; if(is_p != 7) { float t1, t2; t1 = tab1[is_p]; t2 = tab2[is_p]; for( ; sb > 0; sb--, idx += 3) { float v = xr[0][idx]; xr[0][idx] = v * t1; xr[1][idx] = v * t2; } } } /* end for(lwin; .. ; . ) */ /* also check l-part, if ALL bands in the three windows are 'empty' * and mode = mixed_mode */ if(do_l) { int sfb = gr_info->maxbandl; int idx = bi->longIdx[sfb]; for ( ; sfb < 8; sfb++) { int sb = bi->longDiff[sfb]; /* scale: 0-15 */ int is_p = scalefac[sfb]; if(is_p != 7) { float t1, t2; t1 = tab1[is_p]; t2 = tab2[is_p]; for( ; sb > 0; sb--, idx++) { float v = xr[0][idx]; xr[0][idx] = v * t1; xr[1][idx] = v * t2; } } else idx += sb; } } } else { /* ((gr_info->block_type != 2)) */ int sfb = gr_info->maxbandl; int is_p, idx = bi->longIdx[sfb]; for( ; sfb < 21; sfb++) { int sb = bi->longDiff[sfb]; /* scale: 0-15 */ is_p = scalefac[sfb]; if(is_p != 7) { float t1, t2; t1 = tab1[is_p]; t2 = tab2[is_p]; for( ; sb > 0; sb--, idx++) { float v = xr[0][idx]; xr[0][idx] = v * t1; xr[1][idx] = v * t2; } } else idx += sb; } is_p = scalefac[20]; if(is_p != 7) { /* copy l-band 20 to l-band 21 */ int sb; float t1 = tab1[is_p], t2 = tab2[is_p]; for(sb = bi->longDiff[21]; sb > 0; sb--, idx++) { float v = xr[0][idx]; xr[0][idx] = v * t1; xr[1][idx] = v * t2; } } } /* ... */ return 0; } int mpeg3audio_dolayer3(mpeg3_layer_t *audio, char *frame, int frame_size, float **output, int render) { int gr, ch, ss; /* max 39 for short[13][3] mode, mixed: 38, long: 22 */ int scalefacs[2][39]; struct sideinfo_s sideinfo; int single = audio->single; int ms_stereo, i_stereo; int sfreq = audio->sampling_frequency_code; int stereo1, granules; int i; int output_offset = 0; //printf("1\n"); // Skip header frame += 4; frame_size -= 4; /* flip/init buffer */ audio->bsbufold = audio->bsbuf; audio->bsbuf = audio->bsspace[audio->bsnum] + 512; audio->bsnum ^= 1; /* Copy frame into history buffer */ memcpy(audio->bsbuf, frame, frame_size); /* * printf(__FUNCTION__ " %d %02x%02x%02x%02x\n", * audio->first_frame, * (unsigned char)audio->bsbuf[0], * (unsigned char)audio->bsbuf[1], * (unsigned char)audio->bsbuf[2], * (unsigned char)audio->bsbuf[3]); */ if(!audio->first_frame) { /* Set up bitstream to use buffer */ mpeg3bits_use_ptr(audio->stream, audio->bsbuf); //printf(__FUNCTION__ " 4\n"); //printf(__FUNCTION__ " 7 %x\n", mpeg3bits_showbits(audio->stream, 16)); /* CRC must be skipped here for proper alignment with the backstep */ if(audio->error_protection) mpeg3bits_getbits(audio->stream, 16); //printf(__FUNCTION__ " 8 %x\n", mpeg3bits_showbits(audio->stream, 16)); //printf(__FUNCTION__ " 5\n"); if(audio->channels == 1) { /* stream is mono */ stereo1 = 1; single = 0; } else { /* Stereo */ stereo1 = 2; } if(audio->mode == MPG_MD_JOINT_STEREO) { ms_stereo = (audio->mode_ext & 0x2) >> 1; i_stereo = audio->mode_ext & 0x1; } else ms_stereo = i_stereo = 0; if(audio->lsf) { granules = 1; } else { granules = 2; } //printf(__FUNCTION__ " 6\n"); if(get_side_info(audio, &sideinfo, audio->channels, ms_stereo, sfreq, single, audio->lsf)) { mpeg3_layer_reset(audio); return output_offset; } //printf(__FUNCTION__ " 7\n"); /* Step back */ if(sideinfo.main_data_begin >= 512) { return output_offset; } if(sideinfo.main_data_begin) { /* * printf(__FUNCTION__ " 7 %d %d %d\n", * audio->ssize, * sideinfo.main_data_begin, * audio->prev_framesize); */ memcpy(audio->bsbuf + audio->ssize - sideinfo.main_data_begin, audio->bsbufold + audio->prev_framesize - sideinfo.main_data_begin, sideinfo.main_data_begin); mpeg3bits_use_ptr(audio->stream, audio->bsbuf + audio->ssize - sideinfo.main_data_begin); } for(gr = 0; gr < granules; gr++) { float hybridIn [2][SBLIMIT][SSLIMIT]; float hybridOut[2][SSLIMIT][SBLIMIT]; { struct gr_info_s *gr_info = &(sideinfo.ch[0].gr[gr]); int32_t part2bits; if(audio->lsf) part2bits = get_scale_factors_2(audio, scalefacs[0], gr_info, 0); else part2bits = get_scale_factors_1(audio, scalefacs[0], gr_info, 0, gr); //printf("dolayer3 4 %04x\n", mpeg3bits_showbits(audio->stream, 16)); if(dequantize_sample(audio, hybridIn[0], scalefacs[0], gr_info, sfreq, part2bits)) { mpeg3_layer_reset(audio); return output_offset; } //printf("dolayer3 5 %04x\n", mpeg3bits_showbits(audio->stream, 16)); } if(audio->channels == 2) { struct gr_info_s *gr_info = &(sideinfo.ch[1].gr[gr]); int32_t part2bits; if(audio->lsf) part2bits = get_scale_factors_2(audio, scalefacs[1], gr_info, i_stereo); else part2bits = get_scale_factors_1(audio, scalefacs[1], gr_info, 1, gr); if(dequantize_sample(audio, hybridIn[1], scalefacs[1], gr_info, sfreq, part2bits)) { mpeg3_layer_reset(audio); return output_offset; } if(ms_stereo) { int i; int maxb = sideinfo.ch[0].gr[gr].maxb; if(sideinfo.ch[1].gr[gr].maxb > maxb) maxb = sideinfo.ch[1].gr[gr].maxb; for(i = 0; i < SSLIMIT * maxb; i++) { float tmp0 = ((float*)hybridIn[0])[i]; float tmp1 = ((float*)hybridIn[1])[i]; ((float*)hybridIn[0])[i] = tmp0 + tmp1; ((float*)hybridIn[1])[i] = tmp0 - tmp1; } } if(i_stereo) calc_i_stereo(audio, hybridIn, scalefacs[1], gr_info, sfreq, ms_stereo, audio->lsf); if(ms_stereo || i_stereo || (single == 3)) { if(gr_info->maxb > sideinfo.ch[0].gr[gr].maxb) sideinfo.ch[0].gr[gr].maxb = gr_info->maxb; else gr_info->maxb = sideinfo.ch[0].gr[gr].maxb; } switch(single) { case 3: { register int i; register float *in0 = (float*)hybridIn[0], *in1 = (float*)hybridIn[1]; /* *0.5 done by pow-scale */ for(i = 0; i < SSLIMIT * gr_info->maxb; i++, in0++) *in0 = (*in0 + *in1++); } break; case 1: { register int i; register float *in0 = (float*)hybridIn[0], *in1 = (float*)hybridIn[1]; for(i = 0; i < SSLIMIT * gr_info->maxb; i++) *in0++ = *in1++; } break; } } //printf(__FUNCTION__ " 9\n"); for(ch = 0; ch < stereo1; ch++) { struct gr_info_s *gr_info = &(sideinfo.ch[ch].gr[gr]); //printf(__FUNCTION__ " 9.1\n"); antialias(audio, hybridIn[ch], gr_info); //printf(__FUNCTION__ " 9.2\n"); hybrid(audio, hybridIn[ch], hybridOut[ch], ch, gr_info); //printf(__FUNCTION__ " 9.3\n"); } //printf(__FUNCTION__ " 10\n"); for(ss = 0; ss < SSLIMIT; ss++) { if(single >= 0) { if(render) mpeg3audio_synth_stereo(audio, hybridOut[0][ss], 0, output[0], &(output_offset)); else output_offset += 32; } else { int p1 = output_offset; if(render) { mpeg3audio_synth_stereo(audio, hybridOut[0][ss], 0, output[0], &p1); mpeg3audio_synth_stereo(audio, hybridOut[1][ss], 1, output[1], &(output_offset)); } else output_offset += 32; } } } } else { audio->first_frame = 0; } //printf(__FUNCTION__ " 12\n"); return output_offset; } void mpeg3_layer_reset(mpeg3_layer_t *audio) { //printf("mpeg3_layer_reset 1\n"); audio->first_frame = 1; // audio->prev_framesize = 0; // bzero(audio->bsspace, sizeof(audio->bsspace)); bzero(audio->mp3_block, sizeof(audio->mp3_block)); bzero(audio->mp3_blc, sizeof(audio->mp3_blc)); mpeg3audio_reset_synths(audio); } /* Return 1 if the head check doesn't find a header. */ int mpeg3_layer_check(unsigned char *data) { uint32_t head = ((uint32_t)(data[0] << 24)) | ((uint32_t)(data[1] << 16)) | ((uint32_t)(data[2] << 8)) | ((uint32_t)data[3]); if((head & 0xffe00000) != 0xffe00000) return 1; if(!((head >> 17) & 3)) return 1; if(((head >> 12) & 0xf) == 0xf) return 1; if(!((head >> 12) & 0xf)) return 1; if(((head >> 10) & 0x3) == 0x3 ) return 1; if(((head >> 19) & 1) == 1 && ((head >> 17) & 3) == 3 && ((head >> 16) & 1) == 1) return 1; if((head & 0xffff0000) == 0xfffe0000) return 1; // JPEG header if((head & 0xffff0000) == 0xffed0000) return 1; return 0; } /* Decode layer header */ int mpeg3_layer_header(mpeg3_layer_t *audio, unsigned char *data) { uint32_t header; int sampling_frequency_code; int layer; int lsf; int mpeg35; int channels; int mode; if(mpeg3_layer_check(data)) { return 0; } header = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; if(header & (1 << 20)) { lsf = (header & (1 << 19)) ? 0x0 : 0x1; mpeg35 = 0; } else { lsf = 1; mpeg35 = 1; } layer = 4 - ((header >> 17) & 3); //printf("mpeg3_layer_header 1 %08x %d\n", header, layer); if(audio->layer != 0 && layer != audio->layer) { return 0; } if(mpeg35) sampling_frequency_code = 6 + ((header >> 10) & 0x3); else sampling_frequency_code = ((header >> 10) & 0x3) + (lsf * 3); if(audio->samplerate != 0 && sampling_frequency_code != audio->sampling_frequency_code) { return 0; } mode = ((header >> 6) & 0x3); channels = (mode == MPG_MD_MONO) ? 1 : 2; /* * if(audio->channels < 0) * else * if(audio->channels != channels) * return 0; */ // if(channels > audio->channels) // audio->channels = channels; audio->channels = channels; audio->layer = layer; audio->lsf = lsf; audio->mpeg35 = mpeg35; audio->mode = mode; audio->sampling_frequency_code = sampling_frequency_code; audio->samplerate = mpeg3_freqs[audio->sampling_frequency_code]; audio->error_protection = ((header >> 16) & 0x1) ^ 0x1; audio->bitrate_index = ((header >> 12) & 0xf); audio->padding = ((header >> 9) & 0x1); audio->extension = ((header >> 8) & 0x1); audio->mode_ext = ((header >> 4) & 0x3); audio->copyright = ((header >> 3) & 0x1); audio->original = ((header >> 2) & 0x1); audio->emphasis = header & 0x3; if(audio->channels > 1) audio->single = -1; else audio->single = 3; if(!audio->bitrate_index) return 0; audio->bitrate = 1000 * mpeg3_tabsel_123[audio->lsf][audio->layer - 1][audio->bitrate_index]; audio->prev_framesize = audio->framesize - 4; switch(audio->layer) { case 1: audio->framesize = (long)mpeg3_tabsel_123[audio->lsf][0][audio->bitrate_index] * 12000; audio->framesize /= mpeg3_freqs[audio->sampling_frequency_code]; audio->framesize = ((audio->framesize + audio->padding) << 2); break; case 2: audio->framesize = (long)mpeg3_tabsel_123[audio->lsf][1][audio->bitrate_index] * 144000; audio->framesize /= mpeg3_freqs[audio->sampling_frequency_code]; audio->framesize += audio->padding; break; case 3: if(audio->lsf) audio->ssize = (audio->channels == 1) ? 9 : 17; else audio->ssize = (audio->channels == 1) ? 17 : 32; if(audio->error_protection) audio->ssize += 2; audio->framesize = (long)mpeg3_tabsel_123[audio->lsf][2][audio->bitrate_index] * 144000; audio->framesize /= mpeg3_freqs[audio->sampling_frequency_code] << (audio->lsf); audio->framesize = audio->framesize + audio->padding; break; default: return 0; } /* * printf(__FUNCTION__ " bitrate=%d framesize=%d samplerate=%d channels=%d layer=%d\n", * audio->bitrate, * audio->framesize, * audio->samplerate, * audio->channels, * audio->layer); */ if(audio->bitrate < 64000 && audio->layer != 3) return 0; if(audio->framesize > MAXFRAMESIZE) return 0; //printf("mpeg3_layer_header 10 %d\n", layer); return audio->framesize; } mpeg3_layer_t* mpeg3_new_layer() { mpeg3_layer_t *result = calloc(1, sizeof(mpeg3_layer_t)); result->bsbuf = result->bsspace[1]; result->bo = 1; result->channels = -1; result->stream = mpeg3bits_new_stream(0, 0); mpeg3_new_decode_tables(result); return result; } void mpeg3_delete_layer(mpeg3_layer_t *audio) { mpeg3bits_delete_stream(audio->stream); free(audio); } libmpeg3-1.5.4/audio/mantissa.c0000644000175000017500000002344407742725645016554 0ustar enderender00000000000000/* * * mantissa.c Copyright (C) Aaron Holtzman - May 1999 * * * This file is part of libmpeg3 * * libmpeg3 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * libmpeg3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "mpeg3audio.h" /* Lookup tables of 0.16 two's complement quantization values */ static short mpeg3_q_1[3] = { (-2 << 15) / 3, 0, (2 << 15) / 3 }; static short mpeg3_q_2[5] = { (-4 << 15) / 5, ((-2 << 15) / 5) << 1, 0, (2 << 15) / 5, ((4 << 15) / 5) << 1 }; static short mpeg3_q_3[7] = { (-6 << 15) / 7, (-4 << 15) / 7, (-2 << 15) / 7, 0, (2 << 15) / 7, (4 << 15) / 7, (6 << 15) / 7 }; static short mpeg3_q_4[11] = { (-10 << 15) / 11, (-8 << 15) / 11, (-6 << 15) / 11, (-4 << 15) / 11, (-2 << 15) / 11, 0, ( 2 << 15) / 11, ( 4 << 15) / 11, ( 6 << 15) / 11, ( 8 << 15) / 11, (10 << 15) / 11 }; static short mpeg3_q_5[15] = { (-14 << 15) / 15, (-12 << 15) / 15, (-10 << 15) / 15, (-8 << 15) / 15, (-6 << 15) / 15, (-4 << 15) / 15, (-2 << 15) / 15, 0, ( 2 << 15) / 15, ( 4 << 15) / 15, ( 6 << 15) / 15, ( 8 << 15) / 15, (10 << 15) / 15, (12 << 15) / 15, (14 << 15) / 15 }; static short mpeg3_qnttztab[16] = {0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16}; /* */ /* Scale factors for tofloat */ /* */ static const u_int32_t mpeg3_scale_factors[25] = { 0x38000000, /*2 ^ -(0 + 15) */ 0x37800000, /*2 ^ -(1 + 15) */ 0x37000000, /*2 ^ -(2 + 15) */ 0x36800000, /*2 ^ -(3 + 15) */ 0x36000000, /*2 ^ -(4 + 15) */ 0x35800000, /*2 ^ -(5 + 15) */ 0x35000000, /*2 ^ -(6 + 15) */ 0x34800000, /*2 ^ -(7 + 15) */ 0x34000000, /*2 ^ -(8 + 15) */ 0x33800000, /*2 ^ -(9 + 15) */ 0x33000000, /*2 ^ -(10 + 15) */ 0x32800000, /*2 ^ -(11 + 15) */ 0x32000000, /*2 ^ -(12 + 15) */ 0x31800000, /*2 ^ -(13 + 15) */ 0x31000000, /*2 ^ -(14 + 15) */ 0x30800000, /*2 ^ -(15 + 15) */ 0x30000000, /*2 ^ -(16 + 15) */ 0x2f800000, /*2 ^ -(17 + 15) */ 0x2f000000, /*2 ^ -(18 + 15) */ 0x2e800000, /*2 ^ -(19 + 15) */ 0x2e000000, /*2 ^ -(20 + 15) */ 0x2d800000, /*2 ^ -(21 + 15) */ 0x2d000000, /*2 ^ -(22 + 15) */ 0x2c800000, /*2 ^ -(23 + 15) */ 0x2c000000 /*2 ^ -(24 + 15) */ }; static MPEG3_FLOAT32 *mpeg3_scale_factor = (MPEG3_FLOAT32*)mpeg3_scale_factors; #define CLIP(x, y, z) ((x) < (y) ? (y) : ((x) > (z) ? (z) : (x))) static float mpeg3audio_ac3_tofloat(unsigned short exponent, int mantissa) { float x; x = mantissa * mpeg3_scale_factor[CLIP(exponent, 0, 25)]; //printf(__FUNCTION__ " %f\n", x); return x; } static void mpeg3audio_ac3_mantissa_reset(mpeg3_ac3_mantissa_t *mantissa) { mantissa->m_1[2] = mantissa->m_1[1] = mantissa->m_1[0] = 0; mantissa->m_2[2] = mantissa->m_2[1] = mantissa->m_2[0] = 0; mantissa->m_4[1] = mantissa->m_4[0] = 0; /* Force new groups to be loaded */ mantissa->m_1_pointer = mantissa->m_2_pointer = mantissa->m_4_pointer = 3; } /* * Generate eight bits of pseudo-entropy using a 16 bit linear * feedback shift register (LFSR). The primitive polynomial used * is 1 + x^4 + x^14 + x^16. * * The distribution is uniform, over the range [-0.707,0.707] * */ static unsigned int mpeg3audio_ac3_dither_gen(mpeg3audio_t *audio) { int i; unsigned int state; /* explicitly bring the state into a local var as gcc > 3.0? */ /* doesn't know how to optimize out the stores */ state = audio->ac3_lfsr_state; /* Generate eight pseudo random bits */ for(i = 0; i < 8; i++) { state <<= 1; if(state & 0x10000) state ^= 0xa011; } audio->ac3_lfsr_state = state; return (((((int)state << 8) >> 8) * (int)(0.707106f * 256.0f)) >> 16); } /* Fetch an unpacked, left justified, and properly biased/dithered mantissa value */ static unsigned short mpeg3audio_ac3_mantissa_get(mpeg3audio_t *audio, unsigned short bap, unsigned short dithflag) { unsigned short mantissa; unsigned int group_code; mpeg3_ac3_mantissa_t *mantissa_struct = &(audio->ac3_mantissa); /* If the bap is 0-5 then we have special cases to take care of */ switch(bap) { case 0: if(dithflag) mantissa = mpeg3audio_ac3_dither_gen(audio); else mantissa = 0; break; case 1: if(mantissa_struct->m_1_pointer > 2) { group_code = mpeg3bits_getbits(audio->astream, 5); if(group_code > 26) { /* FIXME do proper block error handling */ // fprintf(stderr, "mpeg3audio_ac3_mantissa_get: Invalid mantissa 1 %d\n", group_code); return 0; } mantissa_struct->m_1[0] = group_code / 9; mantissa_struct->m_1[1] = (group_code % 9) / 3; mantissa_struct->m_1[2] = (group_code % 9) % 3; mantissa_struct->m_1_pointer = 0; } mantissa = mantissa_struct->m_1[mantissa_struct->m_1_pointer++]; mantissa = mpeg3_q_1[mantissa]; break; case 2: if(mantissa_struct->m_2_pointer > 2) { group_code = mpeg3bits_getbits(audio->astream, 7); if(group_code > 124) { // fprintf(stderr, "mpeg3audio_ac3_mantissa_get: Invalid mantissa 2 %d\n", group_code); return 0; } mantissa_struct->m_2[0] = group_code / 25; mantissa_struct->m_2[1] = (group_code % 25) / 5; mantissa_struct->m_2[2] = (group_code % 25) % 5; mantissa_struct->m_2_pointer = 0; } mantissa = mantissa_struct->m_2[mantissa_struct->m_2_pointer++]; mantissa = mpeg3_q_2[mantissa]; break; case 3: mantissa = mpeg3bits_getbits(audio->astream, 3); if(mantissa > 6) { // fprintf(stderr, "mpeg3audio_ac3_mantissa_get: Invalid mantissa 3 %d\n", group_code); return 0; } mantissa = mpeg3_q_3[mantissa]; break; case 4: if(mantissa_struct->m_4_pointer > 1) { group_code = mpeg3bits_getbits(audio->astream, 7); if(group_code > 120) { // fprintf(stderr, "mpeg3audio_ac3_mantissa_get: Invalid mantissa 4 %d\n", group_code); return 0; } mantissa_struct->m_4[0] = group_code / 11; mantissa_struct->m_4[1] = group_code % 11; mantissa_struct->m_4_pointer = 0; } mantissa = mantissa_struct->m_4[mantissa_struct->m_4_pointer++]; mantissa = mpeg3_q_4[mantissa]; break; case 5: mantissa = mpeg3bits_getbits(audio->astream, 4); if(mantissa > 14) { /* FIXME do proper block error handling */ // fprintf(stderr, "mpeg3audio_ac3_mantissa_get: Invalid mantissa 5 %d\n", group_code); return 0; } mantissa = mpeg3_q_5[mantissa]; break; default: mantissa = mpeg3bits_getbits(audio->astream, mpeg3_qnttztab[bap]); mantissa <<= 16 - mpeg3_qnttztab[bap]; } return mantissa; } void mpeg3audio_ac3_uncouple_channel(mpeg3audio_t *audio, float samples[], mpeg3_ac3bsi_t *bsi, mpeg3_ac3audblk_t *audblk, unsigned int ch) { unsigned int bnd = 0; unsigned int sub_bnd = 0; unsigned int i, j; MPEG3_FLOAT32 cpl_coord = 1.0; unsigned int cpl_exp_tmp; unsigned int cpl_mant_tmp; short mantissa; for(i = audblk->cplstrtmant; i < audblk->cplendmant; ) { if(!audblk->cplbndstrc[sub_bnd++]) { cpl_exp_tmp = audblk->cplcoexp[ch][bnd] + 3 * audblk->mstrcplco[ch]; if(audblk->cplcoexp[ch][bnd] == 15) cpl_mant_tmp = (audblk->cplcomant[ch][bnd]) << 11; else cpl_mant_tmp = ((0x10) | audblk->cplcomant[ch][bnd]) << 10; cpl_coord = mpeg3audio_ac3_tofloat(cpl_exp_tmp, cpl_mant_tmp) * 8.0f; /*Invert the phase for the right channel if necessary */ if(bsi->acmod == 0x2 && audblk->phsflginu && ch == 1 && audblk->phsflg[bnd]) cpl_coord *= -1; bnd++; } for(j = 0; j < 12; j++) { /* Get new dither values for each channel if necessary, so */ /* the channels are uncorrelated */ if(audblk->dithflag[ch] && audblk->cpl_bap[i] == 0) mantissa = mpeg3audio_ac3_dither_gen(audio); else mantissa = audblk->cplmant[i]; samples[i] = cpl_coord * mpeg3audio_ac3_tofloat(audblk->cpl_exp[i], mantissa);; i++; } } return; } int mpeg3audio_ac3_coeff_unpack(mpeg3audio_t *audio, mpeg3_ac3bsi_t *bsi, mpeg3_ac3audblk_t *audblk, mpeg3ac3_stream_samples_t samples) { int i, j; int done_cpl = 0; short mantissa; mpeg3audio_ac3_mantissa_reset(&(audio->ac3_mantissa)); for(i = 0; i < bsi->nfchans && !mpeg3bits_error(audio->astream); i++) { for(j = 0; j < audblk->endmant[i] && !mpeg3bits_error(audio->astream); j++) { mantissa = mpeg3audio_ac3_mantissa_get(audio, audblk->fbw_bap[i][j], audblk->dithflag[i]); samples[i][j] = mpeg3audio_ac3_tofloat(audblk->fbw_exp[i][j], mantissa); } if(audblk->cplinu && audblk->chincpl[i] && !(done_cpl) && !mpeg3bits_error(audio->astream)) { /* ncplmant is equal to 12 * ncplsubnd */ /* Don't dither coupling channel until channel separation so that * interchannel noise is uncorrelated */ for(j = audblk->cplstrtmant; j < audblk->cplendmant && !mpeg3bits_error(audio->astream); j++) { audblk->cplmant[j] = mpeg3audio_ac3_mantissa_get(audio, audblk->cpl_bap[j], 0); } done_cpl = 1; } } /* Uncouple the channel */ if(audblk->cplinu) { if(audblk->chincpl[i]) mpeg3audio_ac3_uncouple_channel(audio, samples[i], bsi, audblk, i); } if(bsi->lfeon && !mpeg3bits_error(audio->astream)) { /* There are always 7 mantissas for lfe, no dither for lfe */ for(j = 0; j < 7 && !mpeg3bits_error(audio->astream); j++) { mantissa = mpeg3audio_ac3_mantissa_get(audio, audblk->lfe_bap[j], 0); samples[5][j] = mpeg3audio_ac3_tofloat(audblk->lfe_exp[j], mantissa); //printf("%f ", samples[5][j]); } //printf("\n"); } return mpeg3bits_error(audio->astream); } libmpeg3-1.5.4/audio/mpeg3audio.c0000644000175000017500000004125610003145216016741 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include #include static pthread_mutex_t *decode_lock = 0; static void toc_error() { fprintf(stderr, "mpeg3audio: sample accurate seeking without a table of contents \n" "is no longer supported. Use mpeg3toc \n" "to generate a table of contents and load the table of contents instead.\n"); } /* Advance to next header and read it. */ static int read_header(mpeg3audio_t *audio) { int i; int try = 0; int got_it = 0; int result = 0; mpeg3_atrack_t *track = audio->track; switch(track->format) { case AUDIO_AC3: audio->packet_position = 8; result = mpeg3demux_read_data(track->demuxer, audio->packet_buffer + 1, 7); do { try++; for(i = 0; i < 7; i++) audio->packet_buffer[i] = audio->packet_buffer[i + 1]; if(!result) { audio->packet_buffer[7] = mpeg3demux_read_char(track->demuxer); result = mpeg3demux_eof(track->demuxer); } if(!result) { got_it = (mpeg3_ac3_header(audio->ac3_decoder, audio->packet_buffer) != 0); } else break; }while(!result && !got_it && try < 0x10000); if(!result) { if(audio->ac3_decoder->channels > track->channels) track->channels = audio->ac3_decoder->channels; track->sample_rate = audio->ac3_decoder->samplerate; audio->framesize = audio->ac3_decoder->framesize; } break; case AUDIO_MPEG: audio->packet_position = 4; /* Layer 1 not supported */ if(audio->layer_decoder->layer == 1) { result = 1; } result = mpeg3demux_read_data(track->demuxer, audio->packet_buffer + 1, 3); do { try++; for(i = 0; i < 3; i++) audio->packet_buffer[i] = audio->packet_buffer[i + 1]; if(!result) { audio->packet_buffer[3] = mpeg3demux_read_char(track->demuxer); result = mpeg3demux_eof(track->demuxer); } if(!result) { got_it = (mpeg3_layer_header(audio->layer_decoder, audio->packet_buffer) != 0); /* * printf(__FUNCTION__ " got_it=%d packet=%02x%02x%02x%02x\n", * got_it, * (unsigned char)audio->packet_buffer[0], * (unsigned char)audio->packet_buffer[1], * (unsigned char)audio->packet_buffer[2], * (unsigned char)audio->packet_buffer[3]); */ } }while(!result && !got_it && try < 0x10000); if(!result) { if(audio->layer_decoder->channels > track->channels) track->channels = audio->layer_decoder->channels; track->sample_rate = audio->layer_decoder->samplerate; audio->framesize = audio->layer_decoder->framesize; } break; case AUDIO_PCM: audio->packet_position = PCM_HEADERSIZE; result = mpeg3demux_read_data(track->demuxer, audio->packet_buffer + 1, PCM_HEADERSIZE - 1); do { try++; for(i = 0; i < PCM_HEADERSIZE - 1; i++) audio->packet_buffer[i] = audio->packet_buffer[i + 1]; if(!result) { audio->packet_buffer[PCM_HEADERSIZE - 1] = mpeg3demux_read_char(track->demuxer); result = mpeg3demux_eof(track->demuxer); } if(!result) { got_it = (mpeg3_pcm_header(audio->pcm_decoder, audio->packet_buffer) != 0); } }while(!result && !got_it && try < 0x10000); if(!result) { if(audio->pcm_decoder->channels > track->channels) track->channels = audio->pcm_decoder->channels; track->sample_rate = audio->pcm_decoder->samplerate; audio->framesize = audio->pcm_decoder->framesize; } break; } return result; } static int delete_struct(mpeg3audio_t *audio) { int i; mpeg3_atrack_t *track = audio->track; if(audio->output) { for(i = 0; i < track->channels; i++) free(audio->output[i]); free(audio->output); } if(audio->ac3_decoder) mpeg3_delete_ac3(audio->ac3_decoder); if(audio->layer_decoder) mpeg3_delete_layer(audio->layer_decoder); if(audio->pcm_decoder) mpeg3_delete_pcm(audio->pcm_decoder); free(audio); return 0; } static int read_frame(mpeg3audio_t *audio, int render) { int result = 0; mpeg3_atrack_t *track = audio->track; float **temp_output = 0; int samples = 0; int i; int old_channels = track->channels; // Liba52 is not reentrant if(track->format == AUDIO_AC3) { pthread_mutex_lock(decode_lock); } /* Find and read next header */ result = read_header(audio); /* Read rest of frame */ if(!result) { result = mpeg3demux_read_data(track->demuxer, audio->packet_buffer + audio->packet_position, audio->framesize - audio->packet_position); } /* Handle increase in channel count, for ATSC */ if(old_channels < track->channels) { float **new_output = calloc(sizeof(float*), track->channels); for(i = 0; i < track->channels; i++) { new_output[i] = calloc(sizeof(float), audio->output_allocated); if(i < old_channels) memcpy(new_output[i], audio->output[i], sizeof(float) * audio->output_size); } for(i = 0; i < old_channels; i++) free(audio->output[i]); free(audio->output); audio->output = new_output; } if(render) { temp_output = malloc(sizeof(float*) * track->channels); for(i = 0; i < track->channels; i++) { temp_output[i] = audio->output[i] + audio->output_size; } } //printf("read_frame 4 %d %d\n", track->format, audio->layer_decoder->layer); //sleep(1); if(!result) { switch(track->format) { case AUDIO_AC3: samples = mpeg3audio_doac3(audio->ac3_decoder, audio->packet_buffer, audio->framesize, temp_output, render); break; case AUDIO_MPEG: switch(audio->layer_decoder->layer) { case 2: samples = mpeg3audio_dolayer2(audio->layer_decoder, audio->packet_buffer, audio->framesize, temp_output, render); break; case 3: samples = mpeg3audio_dolayer3(audio->layer_decoder, audio->packet_buffer, audio->framesize, temp_output, render); break; default: result = 1; break; } break; case AUDIO_PCM: samples = mpeg3audio_dopcm(audio->pcm_decoder, audio->packet_buffer, audio->framesize, temp_output, render); break; } } audio->output_size += samples; if(render) { free(temp_output); } // Liba52 is not reentrant if(track->format == AUDIO_AC3) { pthread_mutex_unlock(decode_lock); } return samples; } /* Get the length. */ /* Use chunksize if demuxer has a table of contents */ /* For elementary streams use sample count over a certain number of bytes to guess total samples */ /* For program streams use timecode */ static int get_length(mpeg3audio_t *audio) { int result = 0; mpeg3_t *file = audio->file; mpeg3_atrack_t *track = audio->track; int samples = 0; // Table of contents if(track->sample_offsets) { int try = 0; /* Get stream parameters for header validation */ while(samples == 0) { samples = read_frame(audio, 0); } result = track->total_sample_offsets * MPEG3_AUDIO_CHUNKSIZE; } else // Estimate using multiplexed stream size in seconds if(!file->is_audio_stream) { /* Get stream parameters for header validation */ /* Need a table of contents */ while(samples == 0) { samples = read_frame(audio, 0); } // result = (long)(mpeg3demux_length(track->demuxer) * // track->sample_rate); result = 0; } else // Estimate using average bitrate { long test_bytes = 0; long max_bytes = 0x40000; long test_samples = 0; int error = 0; int64_t total_bytes = mpeg3demux_movie_size(track->demuxer); while(!error && test_bytes < max_bytes) { int samples = read_frame(audio, 0); if(!samples) error = 1; test_samples += samples; test_bytes += audio->framesize; } result = (long)(((double)total_bytes / test_bytes) * test_samples + 0.5); } audio->output_size = 0; mpeg3demux_seek_byte(track->demuxer, 0); return result; } mpeg3audio_t* mpeg3audio_new(mpeg3_t *file, mpeg3_atrack_t *track, int format) { mpeg3audio_t *audio = calloc(1, sizeof(mpeg3audio_t)); int result = 0; int i; if(!decode_lock) { pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); decode_lock = calloc(1, sizeof(pthread_mutex_t)); pthread_mutex_init(decode_lock, &attr); } audio->file = file; audio->track = track; audio->byte_seek = -1; audio->sample_seek = -1; track->format = format; //printf("mpeg3audio_new 1 %d\n", result); /* Determine the format of the stream. If it isn't in the first 8 bytes forget it. */ if(track->format == AUDIO_UNKNOWN) { unsigned char header[8]; if(!mpeg3demux_read_data(track->demuxer, header, 8)) { if(!mpeg3_ac3_check(header)) track->format = AUDIO_AC3; else // if(!mpeg3_layer_check(header)) track->format = AUDIO_MPEG; } else result = 1; } //printf("mpeg3audio_new 1 %d\n", result); /* get stream parameters */ if(!result) { switch(track->format) { case AUDIO_AC3: audio->ac3_decoder = mpeg3_new_ac3(); break; case AUDIO_MPEG: audio->layer_decoder = mpeg3_new_layer(); break; case AUDIO_PCM: audio->pcm_decoder = mpeg3_new_pcm(); break; } mpeg3demux_seek_byte(track->demuxer, 0); //printf("mpeg3audio_new 1 %llx\n", mpeg3demux_tell_byte(track->demuxer)); result = read_header(audio); } //printf("mpeg3audio_new 1 %d\n", result); /* Set up the output buffer */ if(!result) { audio->output = calloc(sizeof(float*), track->channels); audio->output_allocated = 4; for(i = 0; i < track->channels; i++) { audio->output[i] = calloc(sizeof(float), audio->output_allocated); } } //printf("mpeg3audio_new 1 %d\n", result); /* Calculate Length */ if(!result) { //printf("mpeg3audio_new 1 %d\n", result); mpeg3demux_seek_byte(track->demuxer, 0); //printf("mpeg3audio_new 1 %d\n", result); track->total_samples = get_length(audio); //printf("mpeg3audio_new 1 %d\n", result); //printf("mpeg3audio_new 1 %d\n", result); } else { delete_struct(audio); audio = 0; } //printf("mpeg3audio_new 2 %p\n", audio); return audio; } static int seek(mpeg3audio_t *audio) { int result = 0; mpeg3_t *file = audio->file; mpeg3_atrack_t *track = audio->track; mpeg3_demuxer_t *demuxer = track->demuxer; int seeked = 0; /* Sample seek was requested */ if(audio->sample_seek >= 0) { /* * printf(__FUNCTION__ " 1 %d %d %d %d\n", * audio->sample_seek, * track->current_position, * audio->output_position, * audio->output_position + audio->output_size); */ /* Don't do anything if the destination is inside the sample buffer */ if(audio->sample_seek >= audio->output_position && audio->sample_seek <= audio->output_position + audio->output_size) { ; } else /* Use table of contents */ if(track->sample_offsets) { int index; int64_t byte; index = audio->sample_seek / MPEG3_AUDIO_CHUNKSIZE; if(index >= track->total_sample_offsets) index = track->total_sample_offsets - 1; byte = track->sample_offsets[index]; mpeg3demux_seek_byte(demuxer, byte); audio->output_position = index * MPEG3_AUDIO_CHUNKSIZE; audio->output_size = 0; seeked = 1; } else if(!file->is_audio_stream) /* Use demuxer */ { toc_error(); /* * double time_position = (double)audio->sample_seek / track->sample_rate; * result |= mpeg3demux_seek_time(demuxer, time_position); */ audio->output_position = audio->sample_seek; audio->output_size = 0; seeked = 1; } else /* Use bitrate */ { int64_t byte = (int64_t)((double)audio->sample_seek / track->total_samples * mpeg3demux_movie_size(demuxer)); //printf(__FUNCTION__ " 5\n"); mpeg3demux_seek_byte(demuxer, byte); audio->output_position = audio->sample_seek; audio->output_size = 0; seeked = 1; } } else /* Percentage seek was requested */ if(audio->byte_seek >= 0) { mpeg3demux_seek_byte(demuxer, audio->byte_seek); // Scan for pts if we're the first to seek. /* * if(file->percentage_pts < 0) * { * file->percentage_pts = mpeg3demux_scan_pts(demuxer); * } * else * { * mpeg3demux_goto_pts(demuxer, file->percentage_pts); * } */ audio->output_position = 0; audio->output_size = 0; seeked = 1; } if(seeked) { mpeg3demux_reset_pts(demuxer); switch(track->format) { case AUDIO_MPEG: mpeg3_layer_reset(audio->layer_decoder); break; } } audio->sample_seek = -1; audio->byte_seek = -1; return 0; } /* ================================================================ */ /* ENTRY POINTS */ /* ================================================================ */ int mpeg3audio_delete(mpeg3audio_t *audio) { delete_struct(audio); return 0; } int mpeg3audio_seek_byte(mpeg3audio_t *audio, int64_t byte) { audio->byte_seek = byte; return 0; } int mpeg3audio_seek_sample(mpeg3audio_t *audio, long sample) { mpeg3_atrack_t *track = audio->track; // Doesn't work for rereading audio during percentage seeking // if(sample > track->total_samples) sample = track->total_samples; if(sample < 0) sample = 0; audio->sample_seek = sample; return 0; } /* Read raw frames for concatenation purposes */ int mpeg3audio_read_raw(mpeg3audio_t *audio, unsigned char *output, long *size, long max_size) { int result = 0; int i; mpeg3_atrack_t *track = audio->track; *size = 0; result = read_header(audio); switch(track->format) { case AUDIO_AC3: /* Just write the AC3 stream */ result = mpeg3demux_read_data(track->demuxer, output, audio->framesize); *size = audio->framesize; break; case AUDIO_MPEG: /* Fix the mpeg stream */ if(!result) { if(mpeg3demux_read_data(track->demuxer, output, audio->framesize)) return 1; *size += audio->framesize; } break; case AUDIO_PCM: if(mpeg3demux_read_data(track->demuxer, output, audio->framesize)) return 1; *size = audio->framesize; break; } return result; } /* Channel is 0 to channels - 1 */ int mpeg3audio_decode_audio(mpeg3audio_t *audio, float *output_f, short *output_i, int channel, long len) { mpeg3_t *file = audio->file; mpeg3_atrack_t *track = audio->track; int i, j, k; int try = 0; int render = 0; long new_size; if(output_f || output_i) render = 1; //printf("mpeg3audio_decode_audio 1\n"); /* Handle seeking requests */ seek(audio); //printf("mpeg3audio_decode_audio 2\n"); new_size = track->current_position + len + MAXFRAMESAMPLES - audio->output_position; //printf(__FUNCTION__ " 1\n"); //printf(__FUNCTION__ " %f\n", mpeg3demux_audio_pts(track->demuxer)); /* Expand output until enough room exists for new data */ if(new_size > audio->output_allocated) { //printf(__FUNCTION__ " 2 %d %d\n", new_size, audio->output_allocated); for(i = 0; i < track->channels; i++) { float *new_output; //printf(__FUNCTION__ " 3\n"); new_output = calloc(sizeof(float), new_size); //printf(__FUNCTION__ " 4\n"); memcpy(new_output, audio->output[i], sizeof(float) * audio->output_size); //printf(__FUNCTION__ " 5\n"); free(audio->output[i]); //printf(__FUNCTION__ " 6\n"); audio->output[i] = new_output; } //printf(__FUNCTION__ " 7\n"); audio->output_allocated = new_size; } /* Decode frames until the output is ready */ while(audio->output_position + audio->output_size < track->current_position + len && try < 256 && !mpeg3demux_eof(track->demuxer)) { //printf("mpeg3audio_decode_audio 8 %d %d\n", try, mpeg3demux_eof(track->demuxer)); int samples = read_frame(audio, render); //printf("mpeg3audio_decode_audio 9 %d\n", samples); if(!samples) try++; else try = 0; } //printf("mpeg3audio_decode_audio 9\n"); /* Copy the buffer to the output */ if(channel >= track->channels) channel = track->channels - 1; if(output_f) { for(i = 0, j = track->current_position - audio->output_position; i < len && j < audio->output_size; i++, j++) { output_f[i] = audio->output[channel][j]; } for( ; i < len; i++) { output_f[i] = 0; } } else if(output_i) { int sample; for(i = 0, j = track->current_position - audio->output_position; i < len && j < audio->output_size; i++, j++) { sample = (int)(audio->output[channel][j] * 32767); if(sample > 32767) sample = 32767; else if(sample < -32768) sample = -32768; output_i[i] = sample; } for( ; i < len; i++) { output_i[i] = 0; } } //printf(__FUNCTION__ " 9 %d %d %d\n", track->channels, audio->output_size, audio->output_allocated); /* Shift audio back */ if(audio->output_size > MPEG3_AUDIO_HISTORY) { int diff = audio->output_size - MPEG3_AUDIO_HISTORY; for(k = 0; k < track->channels; k++) { for(i = 0, j = diff; j < audio->output_size; i++, j++) { audio->output[k][i] = audio->output[k][j]; } } audio->output_size -= diff; audio->output_position += diff; } //printf("mpeg3audio_decode_audio 10 %d %d\n", try, mpeg3demux_eof(track->demuxer)); if(audio->output_size > 0) return 0; else return 1; } libmpeg3-1.5.4/audio/mpeg3audio.h0000644000175000017500000000006207742725645016766 0ustar enderender00000000000000#ifndef MPEG3AUDIO_H #define MPEG3AUDIO_H #endif libmpeg3-1.5.4/audio/pcm.c0000644000175000017500000000415607742725645015513 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include mpeg3_pcm_t* mpeg3_new_pcm() { mpeg3_pcm_t *result = calloc(1, sizeof(mpeg3_pcm_t)); return result; } void mpeg3_delete_pcm(mpeg3_pcm_t *audio) { free(audio); } int mpeg3_pcm_check(unsigned char *header) { if(header[0] == ((MPEG3_PCM_START_CODE & 0xff000000) >> 24) && header[1] == ((MPEG3_PCM_START_CODE & 0xff0000) >> 16) && header[2] == ((MPEG3_PCM_START_CODE & 0xff00) >> 8) && header[3] == (MPEG3_PCM_START_CODE & 0xff)) return 0; else return 1; } int mpeg3_pcm_header(mpeg3_pcm_t *audio, unsigned char *data) { if(mpeg3_pcm_check(data)) return 0; /* Custom header generated by the demuxer */ audio->samplerate = *(int32_t*)(data + 4); audio->bits = *(int32_t*)(data + 8); audio->channels = *(int32_t*)(data + 12); audio->framesize = *(int32_t*)(data + 16); return audio->framesize; } int mpeg3audio_dopcm(mpeg3_pcm_t *audio, char *frame, int frame_size, float **output, int render) { int bytes_per_sample = audio->bits / 8 * audio->channels; int output_size = (frame_size - PCM_HEADERSIZE) / bytes_per_sample; int i, j; //printf("mpeg3audio_dopcm 2 %d\n", frame_size); if(render) { for(i = 0; i < audio->channels; i++) { //printf("mpeg3audio_dopcm 3\n"); float *output_channel = output[i]; //printf("mpeg3audio_dopcm 4\n"); switch(audio->bits) { case 16: { //printf("mpeg3audio_dopcm 5\n"); unsigned char *input = frame + PCM_HEADERSIZE + audio->bits / 8 * i; int16_t sample; //printf("mpeg3audio_dopcm 6\n"); for(j = 0; j < output_size; j++) { sample = ((int16_t)(input[0])) << 8; sample |= input[1]; *output_channel = (float)sample / 32767.0; input += bytes_per_sample; output_channel++; } //printf("mpeg3audio_dopcm 7\n"); } break; } } } /* * printf("mpeg3audio_dopcm 2 %02x%02x%02x%02x\n", * *(unsigned char*)(frame + PCM_HEADERSIZE + 0), * *(unsigned char*)(frame + PCM_HEADERSIZE + 1), * *(unsigned char*)(frame + PCM_HEADERSIZE + 2), * *(unsigned char*)(frame + PCM_HEADERSIZE + 3)); */ return output_size; } libmpeg3-1.5.4/audio/synthesizers.c0000644000175000017500000000635107742725645017505 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include "tables.h" #define WRITE_SAMPLE(samples, sum) \ { \ (*samples) = (sum); \ } int mpeg3audio_synth_stereo(mpeg3_layer_t *audio, float *bandPtr, int channel, float *out, int *pnt) { float *samples = out + *pnt; register float sum; float *b0, (*buf)[0x110]; int bo1; if(!channel) { audio->bo--; audio->bo &= 0xf; buf = audio->synth_stereo_buffs[0]; } else { buf = audio->synth_stereo_buffs[1]; } if(audio->bo & 0x1) { b0 = buf[0]; bo1 = audio->bo; mpeg3audio_dct64(buf[1] + ((audio->bo + 1) & 0xf), buf[0] + audio->bo, bandPtr); } else { b0 = buf[1]; bo1 = audio->bo + 1; mpeg3audio_dct64(buf[0] + audio->bo, buf[1] + audio->bo + 1, bandPtr); } /*printf("%f %f %f\n", buf[0][0], buf[1][0], bandPtr[0]); */ { int j; float *window = mpeg3_decwin + 16 - bo1; for(j = 16; j; j--, b0 += 0x10, window += 0x20, samples++) { sum = window[0x0] * b0[0x0]; sum -= window[0x1] * b0[0x1]; sum += window[0x2] * b0[0x2]; sum -= window[0x3] * b0[0x3]; sum += window[0x4] * b0[0x4]; sum -= window[0x5] * b0[0x5]; sum += window[0x6] * b0[0x6]; sum -= window[0x7] * b0[0x7]; sum += window[0x8] * b0[0x8]; sum -= window[0x9] * b0[0x9]; sum += window[0xA] * b0[0xA]; sum -= window[0xB] * b0[0xB]; sum += window[0xC] * b0[0xC]; sum -= window[0xD] * b0[0xD]; sum += window[0xE] * b0[0xE]; sum -= window[0xF] * b0[0xF]; WRITE_SAMPLE(samples, sum); } sum = window[0x0] * b0[0x0]; sum += window[0x2] * b0[0x2]; sum += window[0x4] * b0[0x4]; sum += window[0x6] * b0[0x6]; sum += window[0x8] * b0[0x8]; sum += window[0xA] * b0[0xA]; sum += window[0xC] * b0[0xC]; sum += window[0xE] * b0[0xE]; WRITE_SAMPLE(samples, sum); b0 -= 0x10; window -= 0x20; samples++; window += bo1 << 1; for(j = 15; j; j--, b0 -= 0x10, window -= 0x20, samples++) { sum = -window[-0x1] * b0[0x0]; sum -= window[-0x2] * b0[0x1]; sum -= window[-0x3] * b0[0x2]; sum -= window[-0x4] * b0[0x3]; sum -= window[-0x5] * b0[0x4]; sum -= window[-0x6] * b0[0x5]; sum -= window[-0x7] * b0[0x6]; sum -= window[-0x8] * b0[0x7]; sum -= window[-0x9] * b0[0x8]; sum -= window[-0xA] * b0[0x9]; sum -= window[-0xB] * b0[0xA]; sum -= window[-0xC] * b0[0xB]; sum -= window[-0xD] * b0[0xC]; sum -= window[-0xE] * b0[0xD]; sum -= window[-0xF] * b0[0xE]; sum -= window[-0x0] * b0[0xF]; WRITE_SAMPLE(samples, sum); } } *pnt += 32; return 0; } /* Call this after every seek to reset the buffers */ int mpeg3audio_reset_synths(mpeg3_layer_t *audio) { int i, j, k; for(i = 0; i < 2; i++) { for(j = 0; j < 2; j++) { for(k = 0; k < 0x110; k++) { audio->synth_stereo_buffs[i][j][k] = 0; } } } for(i = 0; i < 64; i++) { audio->synth_mono_buff[i] = 0; audio->layer2_scfsi_buf[i] = 0; } for(i = 0; i < 2; i++) { for(j = 0; j < 2; j++) { for(k = 0; k < SBLIMIT * SSLIMIT; k++) { audio->mp3_block[i][j][k] = 0; } } } audio->mp3_blc[0] = 0; audio->mp3_blc[1] = 0; return 0; } libmpeg3-1.5.4/audio/tables.c0000644000175000017500000003473007742725645016207 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include "tables.h" #include /* Bitrate indexes */ int mpeg3_tabsel_123[2][3][16] = { { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} }, { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,}, {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,}, {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} } }; long mpeg3_freqs[9] = { 44100, 48000, 32000, 22050, 24000, 16000 , 11025 , 12000 , 8000 }; #ifdef USE_3DNOW float mpeg3_decwin[2 * (512 + 32)]; float mpeg3_cos64[32], mpeg3_cos32[16], mpeg3_cos16[8], mpeg3_cos8[4], mpeg3_cos4[2]; #else float mpeg3_decwin[512 + 32]; float mpeg3_cos64[16], mpeg3_cos32[8], mpeg3_cos16[4], mpeg3_cos8[2], mpeg3_cos4[1]; #endif float *mpeg3_pnts[] = { mpeg3_cos64, mpeg3_cos32, mpeg3_cos16, mpeg3_cos8, mpeg3_cos4 }; int mpeg3_grp_3tab[32 * 3] = { 0, }; /* used: 27 */ int mpeg3_grp_5tab[128 * 3] = { 0, }; /* used: 125 */ int mpeg3_grp_9tab[1024 * 3] = { 0, }; /* used: 729 */ float mpeg3_muls[27][64]; /* also used by layer 1 */ float mpeg3_gainpow2[256 + 118 + 4]; float mpeg3_ispow[8207]; float mpeg3_aa_ca[8], mpeg3_aa_cs[8]; float mpeg3_win[4][36]; float mpeg3_win1[4][36]; float mpeg3_COS1[12][6]; float mpeg3_COS9[9]; float mpeg3_COS6_1, mpeg3_COS6_2; float mpeg3_tfcos36[9]; float mpeg3_tfcos12[3]; float mpeg3_cos9[3], mpeg3_cos18[3]; float mpeg3_tan1_1[16], mpeg3_tan2_1[16], mpeg3_tan1_2[16], mpeg3_tan2_2[16]; float mpeg3_pow1_1[2][16], mpeg3_pow2_1[2][16], mpeg3_pow1_2[2][16], mpeg3_pow2_2[2][16]; long mpeg3_intwinbase[] = { 0, -1, -1, -1, -1, -1, -1, -2, -2, -2, -2, -3, -3, -4, -4, -5, -5, -6, -7, -7, -8, -9, -10, -11, -13, -14, -16, -17, -19, -21, -24, -26, -29, -31, -35, -38, -41, -45, -49, -53, -58, -63, -68, -73, -79, -85, -91, -97, -104, -111, -117, -125, -132, -139, -147, -154, -161, -169, -176, -183, -190, -196, -202, -208, -213, -218, -222, -225, -227, -228, -228, -227, -224, -221, -215, -208, -200, -189, -177, -163, -146, -127, -106, -83, -57, -29, 2, 36, 72, 111, 153, 197, 244, 294, 347, 401, 459, 519, 581, 645, 711, 779, 848, 919, 991, 1064, 1137, 1210, 1283, 1356, 1428, 1498, 1567, 1634, 1698, 1759, 1817, 1870, 1919, 1962, 2001, 2032, 2057, 2075, 2085, 2087, 2080, 2063, 2037, 2000, 1952, 1893, 1822, 1739, 1644, 1535, 1414, 1280, 1131, 970, 794, 605, 402, 185, -45, -288, -545, -814, -1095, -1388, -1692, -2006, -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788, -5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597, -7910, -8209, -8491, -8755, -8998, -9219, -9416, -9585, -9727, -9838, -9916, -9959, -9966, -9935, -9863, -9750, -9592, -9389, -9139, -8840, -8492, -8092, -7640, -7134, -6574, -5959, -5288, -4561, -3776, -2935, -2037, -1082, -70, 998, 2122, 3300, 4533, 5818, 7154, 8540, 9975, 11455, 12980, 14548, 16155, 17799, 19478, 21189, 22929, 24694, 26482, 28289, 30112, 31947, 33791, 35640, 37489, 39336, 41176, 43006, 44821, 46617, 48390, 50137, 51853, 53534, 55178, 56778, 58333, 59838, 61289, 62684, 64019, 65290, 66494, 67629, 68692, 69679, 70590, 71420, 72169, 72835, 73415, 73908, 74313, 74630, 74856, 74992, 75038 }; int mpeg3_longLimit[9][23]; int mpeg3_shortLimit[9][14]; struct mpeg3_bandInfoStruct mpeg3_bandInfo[9] = { /* MPEG 1.0 */ { {0,4,8,12,16,20,24,30,36,44,52,62,74, 90,110,134,162,196,238,288,342,418,576}, {4,4,4,4,4,4,6,6,8, 8,10,12,16,20,24,28,34,42,50,54, 76,158}, {0,4*3,8*3,12*3,16*3,22*3,30*3,40*3,52*3,66*3, 84*3,106*3,136*3,192*3}, {4,4,4,4,6,8,10,12,14,18,22,30,56} } , { {0,4,8,12,16,20,24,30,36,42,50,60,72, 88,106,128,156,190,230,276,330,384,576}, {4,4,4,4,4,4,6,6,6, 8,10,12,16,18,22,28,34,40,46,54, 54,192}, {0,4*3,8*3,12*3,16*3,22*3,28*3,38*3,50*3,64*3, 80*3,100*3,126*3,192*3}, {4,4,4,4,6,6,10,12,14,16,20,26,66} } , { {0,4,8,12,16,20,24,30,36,44,54,66,82,102,126,156,194,240,296,364,448,550,576} , {4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102, 26} , {0,4*3,8*3,12*3,16*3,22*3,30*3,42*3,58*3,78*3,104*3,138*3,180*3,192*3} , {4,4,4,4,6,8,12,16,20,26,34,42,12} } , /* MPEG 2.0 */ { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54 } , {0,4*3,8*3,12*3,18*3,24*3,32*3,42*3,56*3,74*3,100*3,132*3,174*3,192*3} , {4,4,4,6,6,8,10,14,18,26,32,42,18 } } , { {0,6,12,18,24,30,36,44,54,66,80,96,114,136,162,194,232,278,330,394,464,540,576}, {6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,52,64,70,76,36 } , {0,4*3,8*3,12*3,18*3,26*3,36*3,48*3,62*3,80*3,104*3,136*3,180*3,192*3} , {4,4,4,6,8,10,12,14,18,24,32,44,12 } } , { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576}, {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54 }, {0,4*3,8*3,12*3,18*3,26*3,36*3,48*3,62*3,80*3,104*3,134*3,174*3,192*3}, {4,4,4,6,8,10,12,14,18,24,30,40,18 } } , /* MPEG 2.5 */ { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576} , {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54}, {0,12,24,36,54,78,108,144,186,240,312,402,522,576}, {4,4,4,6,8,10,12,14,18,24,30,40,18} }, { {0,6,12,18,24,30,36,44,54,66,80,96,116,140,168,200,238,284,336,396,464,522,576} , {6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54}, {0,12,24,36,54,78,108,144,186,240,312,402,522,576}, {4,4,4,6,8,10,12,14,18,24,30,40,18} }, { {0,12,24,36,48,60,72,88,108,132,160,192,232,280,336,400,476,566,568,570,572,574,576}, {12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2}, {0, 24, 48, 72,108,156,216,288,372,480,486,492,498,576}, {8,8,8,12,16,20,24,28,36,2,2,2,26} } , }; int mpeg3_mapbuf0[9][152]; int mpeg3_mapbuf1[9][156]; int mpeg3_mapbuf2[9][44]; int *mpeg3_map[9][3]; int *mpeg3_mapend[9][3]; unsigned int mpeg3_n_slen2[512]; /* MPEG 2.0 slen for 'normal' mode */ unsigned int mpeg3_i_slen2[256]; /* MPEG 2.0 slen for intensity stereo */ static int init_layer2(mpeg3_layer_t *audio) { static double mulmul[27] = { 0.0 , -2.0/3.0 , 2.0/3.0 , 2.0/7.0 , 2.0/15.0 , 2.0/31.0, 2.0/63.0 , 2.0/127.0 , 2.0/255.0 , 2.0/511.0 , 2.0/1023.0 , 2.0/2047.0 , 2.0/4095.0 , 2.0/8191.0 , 2.0/16383.0 , 2.0/32767.0 , 2.0/65535.0 , -4.0/5.0 , -2.0/5.0 , 2.0/5.0, 4.0/5.0 , -8.0/9.0 , -4.0/9.0 , -2.0/9.0 , 2.0/9.0 , 4.0/9.0 , 8.0/9.0 }; static int base[3][9] = { { 1 , 0, 2 , } , { 17, 18, 0 , 19, 20 , } , { 21, 1, 22, 23, 0, 24, 25, 2, 26 } }; static int tablen[3] = { 3, 5, 9 }; static int *itable, *tables[3] = {mpeg3_grp_3tab, mpeg3_grp_5tab, mpeg3_grp_9tab}; int i, j, k, l, len; float *table; for(i = 0; i < 3; i++) { itable = tables[i]; len = tablen[i]; for(j = 0; j < len; j++) for(k = 0; k < len; k++) for(l = 0; l < len; l++) { *itable++ = base[i][l]; *itable++ = base[i][k]; *itable++ = base[i][j]; } } for(k = 0; k < 27; k++) { double m = mulmul[k]; table = mpeg3_muls[k]; for(j = 3, i = 0; i < 63; i++, j--) *table++ = m * pow(2.0, (double)j / 3.0); *table++ = 0.0; } return 0; } static int init_layer3(mpeg3_layer_t *audio) { int i, j, k, l; int down_sample_sblimit = 32; audio->mp3_block[0][0][0] = 0; audio->mp3_blc[0] = 0; audio->mp3_blc[1] = 0; for(i = -256; i < 118 + 4; i++) mpeg3_gainpow2[i + 256] = pow((double)2.0, -0.25 * (double)(i + 210)); for(i = 0; i < 8207; i++) mpeg3_ispow[i] = pow((double)i, (double)4.0 / 3.0); for(i = 0; i < 8; i++) { static double Ci[8] = {-0.6,-0.535,-0.33,-0.185,-0.095,-0.041,-0.0142,-0.0037}; double sq = sqrt(1.0+Ci[i]*Ci[i]); mpeg3_aa_cs[i] = 1.0/sq; mpeg3_aa_ca[i] = Ci[i]/sq; } for(i = 0; i < 18; i++) { mpeg3_win[0][i] = mpeg3_win[1][i] = 0.5 * sin( M_PI / 72.0 * (double)(2 * (i + 0) + 1) ) / cos (M_PI * (double)(2 * (i + 0) + 19) / 72.0); mpeg3_win[0][i+18] = mpeg3_win[3][i+18] = 0.5 * sin( M_PI / 72.0 * (double)(2 * (i + 18) + 1) ) / cos (M_PI * (double)(2 * (i + 18) + 19) / 72.0); } for(i = 0; i < 6; i++) { mpeg3_win[1][i + 18] = 0.5 / cos ( M_PI * (double) (2*(i+18)+19) / 72.0 ); mpeg3_win[3][i + 12] = 0.5 / cos ( M_PI * (double) (2*(i+12)+19) / 72.0 ); mpeg3_win[1][i + 24] = 0.5 * sin( M_PI / 24.0 * (double)(2 * i + 13) ) / cos (M_PI * (double)(2 * (i + 24)+ 19) / 72.0 ); mpeg3_win[1][i + 30] = mpeg3_win[3][i] = 0.0; mpeg3_win[3][i + 6 ] = 0.5 * sin( M_PI / 24.0 * (double)(2 * i + 1) ) / cos (M_PI * (double)(2 * (i + 6 )+ 19) / 72.0 ); } for(i = 0; i < 9; i++) mpeg3_COS9[i] = cos(M_PI / 18.0 * (double)i); for(i = 0; i < 9; i++) mpeg3_tfcos36[i] = 0.5 / cos (M_PI * (double) (i*2+1) / 36.0); for(i = 0; i < 3; i++) mpeg3_tfcos12[i] = 0.5 / cos (M_PI * (double) (i*2+1) / 12.0); mpeg3_COS6_1 = cos( M_PI / 6.0 * (double) 1); mpeg3_COS6_2 = cos( M_PI / 6.0 * (double) 2); mpeg3_cos9[0] = cos(1.0 * M_PI / 9.0); mpeg3_cos9[1] = cos(5.0 * M_PI / 9.0); mpeg3_cos9[2] = cos(7.0 * M_PI / 9.0); mpeg3_cos18[0] = cos(1.0 * M_PI / 18.0); mpeg3_cos18[1] = cos(11.0 * M_PI / 18.0); mpeg3_cos18[2] = cos(13.0 * M_PI / 18.0); for(i = 0; i < 12; i++) { mpeg3_win[2][i] = 0.5 * sin(M_PI / 24.0 * (double) (2 * i + 1)) / cos(M_PI * (double)(2 * i + 7) / 24.0); for(j = 0; j < 6; j++) mpeg3_COS1[i][j] = cos(M_PI / 24.0 * (double) ((2 * i + 7) * (2 * j + 1))); } for(j = 0; j < 4; j++) { static int len[4] = {36, 36, 12, 36}; for(i = 0; i < len[j]; i += 2) mpeg3_win1[j][i] = + mpeg3_win[j][i]; for(i = 1; i < len[j]; i += 2) mpeg3_win1[j][i] = - mpeg3_win[j][i]; } for(i = 0; i < 16; i++) { double t = tan( (double) i * M_PI / 12.0 ); mpeg3_tan1_1[i] = t / (1.0 + t); mpeg3_tan2_1[i] = 1.0 / (1.0 + t); mpeg3_tan1_2[i] = M_SQRT2 * t / (1.0 + t); mpeg3_tan2_2[i] = M_SQRT2 / (1.0 + t); for(j = 0; j < 2; j++) { double base = pow(2.0, -0.25 * (j + 1.0)); double p1 = 1.0,p2 = 1.0; if(i > 0) { if( i & 1 ) p1 = pow(base, (i + 1.0) * 0.5); else p2 = pow(base, i * 0.5); } mpeg3_pow1_1[j][i] = p1; mpeg3_pow2_1[j][i] = p2; mpeg3_pow1_2[j][i] = M_SQRT2 * p1; mpeg3_pow2_2[j][i] = M_SQRT2 * p2; } } for(j = 0; j < 9; j++) { struct mpeg3_bandInfoStruct *bi = &mpeg3_bandInfo[j]; int *mp; int cb,lwin; int *bdf; mp = mpeg3_map[j][0] = mpeg3_mapbuf0[j]; bdf = bi->longDiff; for(i = 0, cb = 0; cb < 8; cb++, i += *bdf++) { *mp++ = (*bdf) >> 1; *mp++ = i; *mp++ = 3; *mp++ = cb; } bdf = bi->shortDiff + 3; for(cb = 3; cb < 13; cb++) { int l = (*bdf++) >> 1; for(lwin = 0; lwin < 3; lwin++) { *mp++ = l; *mp++ = i + lwin; *mp++ = lwin; *mp++ = cb; } i += 6 * l; } mpeg3_mapend[j][0] = mp; mp = mpeg3_map[j][1] = mpeg3_mapbuf1[j]; bdf = bi->shortDiff+0; for(i = 0,cb = 0; cb < 13; cb++) { int l = (*bdf++) >> 1; for(lwin = 0; lwin < 3; lwin++) { *mp++ = l; *mp++ = i + lwin; *mp++ = lwin; *mp++ = cb; } i += 6 * l; } mpeg3_mapend[j][1] = mp; mp = mpeg3_map[j][2] = mpeg3_mapbuf2[j]; bdf = bi->longDiff; for(cb = 0; cb < 22 ; cb++) { *mp++ = (*bdf++) >> 1; *mp++ = cb; } mpeg3_mapend[j][2] = mp; } for(j = 0; j < 9; j++) { for(i = 0; i < 23; i++) { mpeg3_longLimit[j][i] = (mpeg3_bandInfo[j].longIdx[i] - 1 + 8) / 18 + 1; if(mpeg3_longLimit[j][i] > (down_sample_sblimit)) mpeg3_longLimit[j][i] = down_sample_sblimit; } for(i = 0; i < 14; i++) { mpeg3_shortLimit[j][i] = (mpeg3_bandInfo[j].shortIdx[i] - 1) / 18 + 1; if(mpeg3_shortLimit[j][i] > (down_sample_sblimit) ) mpeg3_shortLimit[j][i] = down_sample_sblimit; } } for(i = 0; i < 5; i++) { for(j = 0; j < 6; j++) { for(k = 0; k < 6; k++) { int n = k + j * 6 + i * 36; mpeg3_i_slen2[n] = i | (j << 3) | (k << 6) | (3 << 12); } } } for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { for(k = 0; k < 4; k++) { int n = k + j * 4 + i * 16; mpeg3_i_slen2[n+180] = i | (j << 3) | (k << 6) | (4 << 12); } } } for(i = 0; i < 4; i++) { for(j = 0; j < 3; j++) { int n = j + i * 3; mpeg3_i_slen2[n + 244] = i | (j << 3) | (5 << 12); mpeg3_n_slen2[n + 500] = i | (j << 3) | (2 << 12) | (1 << 15); } } for(i = 0; i < 5; i++) { for(j = 0; j < 5; j++) { for(k = 0; k < 4; k++) { for(l = 0; l < 4; l++) { int n = l + k * 4 + j * 16 + i * 80; mpeg3_n_slen2[n] = i | (j << 3) | ( k << 6) | (l << 9) | (0 << 12); } } } } for(i = 0; i < 5; i++) { for(j = 0; j < 5; j++) { for(k = 0; k < 4; k++) { int n = k + j * 4 + i * 20; mpeg3_n_slen2[n + 400] = i | (j << 3) | (k << 6) | (1 << 12); } } } return 0; } int mpeg3_new_decode_tables(mpeg3_layer_t *audio) { int i, j, k, kr, divv; float *costab; int idx; long scaleval = 1; for(i = 0; i < 5; i++) { kr = 0x10 >> i; divv = 0x40 >> i; costab = mpeg3_pnts[i]; for(k = 0; k < kr; k++) costab[k] = 1.0 / (2.0 * cos(M_PI * ((double)k * 2.0 + 1.0) / (double)divv)); #ifdef USE_3DNOW for(k = 0; k < kr; k++) costab[k + kr] = -costab[k]; #endif } idx = 0; scaleval = -scaleval; for(i = 0, j = 0; i < 256; i++, j++,idx += 32) { if(idx < 512 + 16) mpeg3_decwin[idx+16] = mpeg3_decwin[idx] = (double)mpeg3_intwinbase[j] / 65536.0 * (double)scaleval; if(i % 32 == 31) idx -= 1023; if(i % 64 == 63) scaleval = -scaleval; } for( ; i < 512; i++, j--, idx += 32) { if(idx < 512 + 16) mpeg3_decwin[idx + 16] = mpeg3_decwin[idx] = (double)mpeg3_intwinbase[j] / 65536.0 * (double)scaleval; if(i % 32 == 31) idx -= 1023; if(i % 64 == 63) scaleval = -scaleval; } #ifdef USE_3DNOW if(!param.down_sample) { for(i = 0; i < 512 + 32; i++) { mpeg3_decwin[512 + 31 - i] *= 65536.0; /* allows faster clipping in 3dnow code */ mpeg3_decwin[512 + 32 + i] = mpeg3_decwin[512 + 31 - i]; } } #endif /* Initialize AC3 */ // mpeg3audio_imdct_init(audio); /* Initialize MPEG */ init_layer2(audio); /* inits also shared tables with layer1 */ init_layer3(audio); return 0; } libmpeg3-1.5.4/audio/tables.h0000644000175000017500000000317407742725645016212 0ustar enderender00000000000000#ifndef TABLES_H #define TABLES_H extern int mpeg3_tabsel_123[2][3][16]; extern long mpeg3_freqs[9]; struct mpeg3_bandInfoStruct { int longIdx[23]; int longDiff[22]; int shortIdx[14]; int shortDiff[13]; }; extern float mpeg3_decwin[512 + 32]; extern float mpeg3_cos64[16], mpeg3_cos32[8], mpeg3_cos16[4], mpeg3_cos8[2], mpeg3_cos4[1]; extern float *mpeg3_pnts[5]; extern int mpeg3_grp_3tab[32 * 3]; /* used: 27 */ extern int mpeg3_grp_5tab[128 * 3]; /* used: 125 */ extern int mpeg3_grp_9tab[1024 * 3]; /* used: 729 */ extern float mpeg3_muls[27][64]; /* also used by layer 1 */ extern float mpeg3_gainpow2[256 + 118 + 4]; extern long mpeg3_intwinbase[257]; extern float mpeg3_ispow[8207]; extern float mpeg3_aa_ca[8], mpeg3_aa_cs[8]; extern float mpeg3_win[4][36]; extern float mpeg3_win1[4][36]; extern float mpeg3_COS1[12][6]; extern float mpeg3_COS9[9]; extern float mpeg3_COS6_1, mpeg3_COS6_2; extern float mpeg3_tfcos36[9]; extern float mpeg3_tfcos12[3]; extern float mpeg3_cos9[3], mpeg3_cos18[3]; extern float mpeg3_tan1_1[16], mpeg3_tan2_1[16], mpeg3_tan1_2[16], mpeg3_tan2_2[16]; extern float mpeg3_pow1_1[2][16], mpeg3_pow2_1[2][16], mpeg3_pow1_2[2][16], mpeg3_pow2_2[2][16]; extern int mpeg3_longLimit[9][23]; extern int mpeg3_shortLimit[9][14]; extern struct mpeg3_bandInfoStruct mpeg3_bandInfo[9]; extern int mpeg3_mapbuf0[9][152]; extern int mpeg3_mapbuf1[9][156]; extern int mpeg3_mapbuf2[9][44]; extern int *mpeg3_map[9][3]; extern int *mpeg3_mapend[9][3]; extern unsigned int mpeg3_n_slen2[512]; /* MPEG 2.0 slen for 'normal' mode */ extern unsigned int mpeg3_i_slen2[256]; /* MPEG 2.0 slen for intensity stereo */ #endif libmpeg3-1.5.4/audio/uncouple.c0000644000175000017500000000676307742725645016574 0ustar enderender00000000000000/* * * uncouple.c Copyright (C) Aaron Holtzman - May 1999 * * This file is part of libmpeg3 * * libmpeg3 is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * libmpeg3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include "../bitstream.h" #include "mpeg3audio.h" static unsigned char mpeg3_first_bit_lut[256] = { 0, 8, 7, 7, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; /* Converts an unsigned exponent in the range of 0-24 and a 16 bit mantissa * to an IEEE single precision floating point value */ static inline void mpeg3audio_ac3_convert_to_float(unsigned short exp, unsigned short mantissa, u_int32_t *dest) { int num; short exponent; int i; /* If the mantissa is zero we can simply return zero */ if(mantissa == 0) { *dest = 0; return; } /* Exponent is offset by 127 in IEEE format minus the shift to * align the mantissa to 1.f (subtracted in the final result) */ exponent = 127 - exp; /* Take care of the one asymmetric negative number */ if(mantissa == 0x8000) mantissa++; /* Extract the sign bit, invert the mantissa if it's negative, and shift out the sign bit */ if(mantissa & 0x8000) { mantissa *= -1; num = 0x80000000 + (exponent << 23); } else { mantissa *= 1; num = exponent << 23; } /* Find the index of the most significant one bit */ i = mpeg3_first_bit_lut[mantissa >> 8]; if(i == 0) i = mpeg3_first_bit_lut[mantissa & 0xff] + 8; *dest = num - (i << 23) + (mantissa << (7 + i)); return; } int mpeg3audio_ac3_uncouple(mpeg3audio_t *audio, mpeg3_ac3bsi_t *bsi, mpeg3_ac3audblk_t *audblk, mpeg3_stream_coeffs_t *coeffs) { int i, j; for(i = 0; i < bsi->nfchans; i++) { for(j = 0; j < audblk->endmant[i]; j++) mpeg3audio_ac3_convert_to_float(audblk->fbw_exp[i][j], audblk->chmant[i][j], (u_int32_t*)&coeffs->fbw[i][j]); } if(audblk->cplinu) { for(i = 0; i < bsi->nfchans; i++) { if(audblk->chincpl[i]) { mpeg3audio_ac3_uncouple_channel(audio, coeffs, audblk, i); } } } if(bsi->lfeon) { /* There are always 7 mantissas for lfe */ for(j = 0; j < 7 ; j++) mpeg3audio_ac3_convert_to_float(audblk->lfe_exp[j], audblk->lfemant[j], (u_int32_t*)&coeffs->lfe[j]); } return 0; } libmpeg3-1.5.4/bitstream.c0000644000175000017500000001027207766475057015626 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include mpeg3_bits_t* mpeg3bits_new_stream(mpeg3_t *file, mpeg3_demuxer_t *demuxer) { mpeg3_bits_t *stream = malloc(sizeof(mpeg3_bits_t)); stream->bfr = 0; stream->bfr_size = 0; stream->bit_number = 0; stream->file = file; stream->demuxer = demuxer; stream->input_ptr = 0; return stream; } int mpeg3bits_delete_stream(mpeg3_bits_t* stream) { free(stream); return 0; } /* Fill a buffer. Only works if bit_number is on an 8 bit boundary */ int mpeg3bits_read_buffer(mpeg3_bits_t* stream, unsigned char *buffer, int bytes) { int result, i = 0; while(stream->bit_number > 0) { stream->bit_number -= 8; mpeg3demux_read_prev_char(stream->demuxer); } stream->bit_number = 0; stream->bfr_size = 0; stream->bfr = 0; result = mpeg3demux_read_data(stream->demuxer, buffer, bytes); return result; } /* For mp3 decompression use a pointer in a buffer for getbits. */ int mpeg3bits_use_ptr(mpeg3_bits_t* stream, unsigned char *buffer) { stream->bfr_size = stream->bit_number = 0; stream->bfr = 0; stream->input_ptr = buffer; return 0; } /* Go back to using the demuxer for getbits in mp3. */ int mpeg3bits_use_demuxer(mpeg3_bits_t* stream) { if(stream->input_ptr) { stream->bfr_size = stream->bit_number = 0; stream->input_ptr = 0; stream->bfr = 0; } return 0; } /* Reconfigure for reverse operation */ /* Default is forward operation */ void mpeg3bits_start_reverse(mpeg3_bits_t* stream) { int i; for(i = 0; i < stream->bfr_size; i += 8) { if(stream->input_ptr) stream->input_ptr--; else mpeg3demux_read_prev_char(stream->demuxer); } } /* Reconfigure for forward operation */ void mpeg3bits_start_forward(mpeg3_bits_t* stream) { int i; // If already at the bof, the buffer is already invalid. if(stream->demuxer && mpeg3bits_bof(stream)) { stream->bfr_size = 0; stream->bit_number = 0; stream->bfr = 0; stream->input_ptr = 0; mpeg3demux_read_char(stream->demuxer); } else for(i = 0; i < stream->bfr_size; i += 8) { if(stream->input_ptr) stream->input_ptr++; else mpeg3demux_read_char(stream->demuxer); } } /* Erase the buffer with the next 4 bytes in the file. */ int mpeg3bits_refill(mpeg3_bits_t* stream) { stream->bit_number = 32; stream->bfr_size = 32; if(stream->input_ptr) { stream->bfr = (unsigned int)(*stream->input_ptr++) << 24; stream->bfr |= (unsigned int)(*stream->input_ptr++) << 16; stream->bfr |= (unsigned int)(*stream->input_ptr++) << 8; stream->bfr |= *stream->input_ptr++; } else { stream->bfr = mpeg3demux_read_char(stream->demuxer) << 24; stream->bfr |= mpeg3demux_read_char(stream->demuxer) << 16; stream->bfr |= mpeg3demux_read_char(stream->demuxer) << 8; stream->bfr |= mpeg3demux_read_char(stream->demuxer); } return mpeg3demux_eof(stream->demuxer); } /* Erase the buffer with the previous 4 bytes in the file. */ int mpeg3bits_refill_backwards(mpeg3_bits_t* stream) { stream->bit_number = 0; stream->bfr_size = 32; stream->bfr = mpeg3demux_read_prev_char(stream->demuxer); stream->bfr |= (unsigned int)mpeg3demux_read_prev_char(stream->demuxer) << 8; stream->bfr |= (unsigned int)mpeg3demux_read_prev_char(stream->demuxer) << 16; stream->bfr |= (unsigned int)mpeg3demux_read_prev_char(stream->demuxer) << 24; return mpeg3demux_eof(stream->demuxer); } int mpeg3bits_byte_align(mpeg3_bits_t *stream) { stream->bit_number = (stream->bit_number + 7) & 0xf8; return 0; } int mpeg3bits_open_title(mpeg3_bits_t* stream, int title) { stream->bfr_size = stream->bit_number = 0; return mpeg3demux_open_title(stream->demuxer, title); } /* * int mpeg3bits_seek_time(mpeg3_bits_t* stream, double time_position) * { * stream->bfr_size = stream->bit_number = 0; * return mpeg3demux_seek_time(stream->demuxer, time_position); * } */ int mpeg3bits_seek_byte(mpeg3_bits_t* stream, int64_t position) { stream->bfr_size = stream->bit_number = 0; return mpeg3demux_seek_byte(stream->demuxer, position); } void mpeg3bits_reset(mpeg3_bits_t *stream) { stream->bfr_size = stream->bit_number = 0; } int64_t mpeg3bits_tell(mpeg3_bits_t* stream) { return mpeg3demux_tell_byte(stream->demuxer); } int mpeg3bits_getbitoffset(mpeg3_bits_t *stream) { return stream->bit_number & 7; } libmpeg3-1.5.4/bitstream.h0000644000175000017500000000014007742725645015617 0ustar enderender00000000000000#ifndef BITSTREAM_H #define BITSTREAM_H #include "mpeg3demux.h" #include #endif libmpeg3-1.5.4/configure0000755000175000017500000000110507744163160015353 0ustar enderender00000000000000# configuration is being done in a script because starting with GCC-3.2 # the compiler flags are changing too much between minor releases to detect # with Makefile scripts alone. For now it just tells you if you have the # prerequisite compilers. ERROR=0 # test for nasm if [ -x /usr/bin/nasm -o -x /usr/local/bin/nasm ]; then HAVE_NASM=y; else HAVE_NASM=n; fi if [ $HAVE_NASM == n ]; then echo " *** Nasm is required. Download it from nasm.sourceforge.net"; ERROR=1 fi # success if [ $ERROR == 0 ]; then echo "Configured successfully. Type 'make' to build it."; fi libmpeg3-1.5.4/COPYING0000644000175000017500000004316307742725645014523 0ustar enderender00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The \"Program\", below, refers to any such program or work, and a \"work based on the Program\" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term \"modification\".) Each licensee is addressed as \"you\". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and \"any later version\", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the \"copyright\" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a \"copyright disclaimer\" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. libmpeg3-1.5.4/depend.a520000644000175000017500000000231007742725645015225 0ustar enderender00000000000000 $(OBJDIR)/$(A52DIR)/liba52/imdct_mlib.o: $(A52DIR)/liba52/imdct_mlib.c $(OBJDIR)/$(A52DIR)/liba52/bitstream.o: $(A52DIR)/liba52/bitstream.c $(OBJDIR)/$(A52DIR)/liba52/bit_allocate.o: $(A52DIR)/liba52/bit_allocate.c $(OBJDIR)/$(A52DIR)/liba52/imdct.o: $(A52DIR)/liba52/imdct.c $(OBJDIR)/$(A52DIR)/liba52/downmix.o: $(A52DIR)/liba52/downmix.c $(OBJDIR)/$(A52DIR)/liba52/parse.o: $(A52DIR)/liba52/parse.c $(OBJDIR)/$(A52DIR)/libao/audio_out.o: $(A52DIR)/libao/audio_out.c $(OBJDIR)/$(A52DIR)/libao/audio_out_solaris.o: $(A52DIR)/libao/audio_out_solaris.c $(OBJDIR)/$(A52DIR)/libao/float2s16.o: $(A52DIR)/libao/float2s16.c $(OBJDIR)/$(A52DIR)/libao/audio_out_null.o: $(A52DIR)/libao/audio_out_null.c $(OBJDIR)/$(A52DIR)/libao/audio_out_float.o: $(A52DIR)/libao/audio_out_float.c $(OBJDIR)/$(A52DIR)/libao/audio_out_wav.o: $(A52DIR)/libao/audio_out_wav.c $(OBJDIR)/$(A52DIR)/libao/audio_out_oss.o: $(A52DIR)/libao/audio_out_oss.c $(OBJDIR)/$(A52DIR)/src/getopt.o: $(A52DIR)/src/getopt.c $(OBJDIR)/$(A52DIR)/src/extract_a52.o: $(A52DIR)/src/extract_a52.c $(OBJDIR)/$(A52DIR)/src/a52dec.o: $(A52DIR)/src/a52dec.c $(OBJDIR)/$(A52DIR)/test/compare.o: $(A52DIR)/test/compare.c libmpeg3-1.5.4/docs/0000755000175000017500000000000010012353221014354 5ustar enderender00000000000000libmpeg3-1.5.4/docs/index.html0000644000175000017500000004034607754111320016373 0ustar enderender00000000000000LibMPEG3
Using LibMPEG3 for advanced MPEG decoding

Author: Heroine Virtual Ltd. (Motion picture solutions for Linux without a warranty) Harassment: broadcast@earthling.net
Homepage: heroinewarrior.com

libmpeg3 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version.

libmpeg3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

In addition to the GPL's warranty stipulation, libmpeg3 is distributed WITHOUT GUARANTEED SUPPORT. Support that is not guaranteed includes technical support, compiler troubleshooting, debugging, version matching, updating, among other additional labor which may or may not be required to meet a user's requirements.

Table of contents

Intro
Building the library
Usage
Using tables of contents for editing

LibMPEG3 decodes several MPEG standards into uncompressed data suitable for editing and playback.

libmpeg3 currently decodes:

MPEG-2 video
MPEG-1 video
mp3 audio
mp2 audio
ac3 audio
MPEG-2 transport streams
MPEG-2 program streams
MPEG-1 program streams
IFO files

The video output can be in many different color models and frame sizes. The audio output can be in twos compliment or floating point. Frame accurate seeking, normally impossible in transport streams, is possible in libmpeg3 through the use of a table of contents. MPEG-2 video in YUV-422 colorspace is decodable. Digital TV broadcasts and DVD's can be edited using libmpeg3. Libmpeg3 takes what is normally a last mile distribution format and makes it editable.

Because of these and other features libmpeg3 is not intended for consumer applications but serves users who are interested in high quality editing and footage acquisition.

Building the library

libmpeg3 depends on the CFLAGS environment variable to get optimization flags. You should set it to

-O3 -march=i686 -fmessage-length=0 -funroll-all-loops -fomit-frame-pointer -malign-loops=2 -malign-jumps=2 -malign-functions=2

You must run make to build the library and should be using Kernel 2.4.9 or later. The makefile automatically determines appropriate parameters and puts the library in i686/libmpeg3.a. Several utilities are also built. Install the utilities by running make install.

Unfortunately libmpeg3 excercizes the system more aggressively than a consumer library and this brings out different bugs in each kernel version.

2.4.9: ext3 filesystem failure
2.4.10: memory management failure when running mpeg3toc
2.4.17: memory management failure after 5 hours of decoding video

As libmpeg3 is not one of the standard MPEG decoding libraries, these utilities are unlike any you've ever seen before. Remember a utility is only as illegal or legal as the guy who runs it.

Usage

STEP 1: Verifying file compatibility

Programs using libmpeg3 must #include "libmpeg3.h".

Call mpeg3_check_sig to verify if the file can be read by libmpeg3. This returns a 1 if it is compatible and 0 if it isn't.

STEP 2: Open the file

You need an mpeg3_t* file descriptor:

mpeg3_t* file;

Then you need to open the file:

file = mpeg3_open(char *path);

mpeg3_open returns a NULL if the file couldn't be opened for some reason. Be sure to check this. Everything you do with libmpeg3 requires passing the file pointer.

Another way of opening a file is

mpeg3_open_copy(char *path, mpeg3_t *old_file)

You need to open multiple copies of a file in realtime situations because only one thread can access a mpeg3_t structure at a time. The audio and video can't read simultaneously. The solution is not to repeatedly call mpeg3_open but to call mpeg3_open_copy for every file handle after the first one. This copies tables from the first file to speed up opening.

STEP 3: Set optimization strategies

Call mpeg3_set_cpus(mpeg3_t *file, int cpus) to set how many CPUs should be devoted to video decompression. LibMPEG3 can use any number.

Call mpeg3_set_mmx(mpeg3_t *file, int use_mmx) to set if MMX is used for video. Disabling MMX is mandatory for low bitrate streams since it is very lossy. By the way, lately the compiled MMX output has been producing corrupted video. This is a change in the way modern compilers and CPU's handle MMX from the way it was done 4 years ago but since modern CPU's are so fast, you're better off not using MMX at all.

STEP 4: Query the file.

There are a number of queries for the audio components of the stream:

int mpeg3_has_audio(mpeg3_t *file);
int mpeg3_total_astreams(mpeg3_t *file);             // Number of multiplexed audio streams
int mpeg3_audio_channels(mpeg3_t *file, int stream);
int mpeg3_sample_rate(mpeg3_t *file, int stream);
long mpeg3_audio_samples(mpeg3_t *file, int stream); // Total length
The audio is presented as a number of streams starting at 0 and including mpeg3_total_astreams - 1. Each stream contains a certain number of channels starting at 0 and including mpeg3_audio_channels - 1. The methodology is first determine if the file has audio, then get the number of streams in the file, then for each stream get the number of channels, sample rate, and length.

There are also queries for the video components:

int mpeg3_has_video(mpeg3_t *file);
int mpeg3_total_vstreams(mpeg3_t *file);            // Number of multiplexed video streams
int mpeg3_video_width(mpeg3_t *file, int stream);
int mpeg3_video_height(mpeg3_t *file, int stream);
float mpeg3_frame_rate(mpeg3_t *file, int stream);  // Frames/sec
long mpeg3_video_frames(mpeg3_t *file, int stream); // Total length
int mpeg3_colormodel(mpeg3_t *file, int stream);
The video behavior is the same as with audio, except that video has no subdivision under streams. Frame rate is a floating point number of frames per second.

mpeg3_colormodel returns either MPEG3_YUV420P or MPEG3_YUV422P. MPEG3_YUV422P is only encountered in high quality video not available in any consumer distribution medium.

STEP 5: Seeking to a point in the file

Each audio stream and each video stream has a position in the file independant of each other stream. A variety of methods are available for specifying the position of a stream: byte offset, frame, sample. Which method you use depends on whether you're seeking audio or video and whether you have a table of contents for the stream.

The preferred seeking method if you're writing a player is:

int mpeg3_seek_byte(mpeg3_t *file, int64_t byte);
int64_t mpeg3_tell_byte(mpeg3_t *file);
This seeks all tracks to an absolute byte offset in the file. The byte offset is from 0 to the result of:

mpeg3_get_bytes(mpeg3_t *file)
The alternative to byte seeking is frame or sample seeking. Frame seeking is only possible if a table of contents exists. The mpeg3toc that comes with libmpeg3 creates tables of contents from MPEG 1 & 2 streams. Sample seeking is only possible if the stream is fixed bitrate audio. The audio seeking is handled by:

int mpeg3_set_sample(mpeg3_t *file, long sample, int stream);    // Seek
long mpeg3_get_sample(mpeg3_t *file, int stream);    // Tell current position
and the video seeking is handled by:

int mpeg3_set_frame(mpeg3_t *file, long frame, int stream); // Seek
long mpeg3_get_frame(mpeg3_t *file, int stream);            // Tell current position
You can either perform percentage seeking or absolute byte seeking but not both on the same file handle. Once you perform either method, the file becomes configured for that method.

If you're in byte seeking mode and you want the current time stamp in the file you can't use mpeg3_get_frame or mpeg3_get_sample because you don't know the total length in the desired units. The mpeg3_audio_samples and mpeg3_video_frames commands don't work in percentage seeking either. Instead use

double mpeg3_get_time(mpeg3_t *file);
which gives you the last timecode read in seconds. The MPEG standard specifies timecodes being placed in the streams. Now you know the absolute byte position in the file and the current time stamp, enough to update a progress bar or a text box.

Finally, there is a way to seek to the previous frame of video:

int mpeg3_previous_frame(mpeg3_t *file, int stream);
Because MPEG 1 & 2 are really hairy, the set commands won't do much good for playing backwards. mpeg3_previous_frame does some tricks to seek to the previous frame. Next you have to call a read_frame command to read it.

STEP 6: Read the data

To read audio data use:

int mpeg3_read_audio(mpeg3_t *file, 
		float *output_f,      // Pointer to pre-allocated buffer of floats
		short *output_i,      // Pointer to pre-allocated buffer if int16's
		int channel,          // Channel to decode
		long samples,         // Number of samples to decode
		int stream);          // Stream containing the channel
This decodes a buffer of sequential floats or int16's for a single channel, depending on which *output... parameter has a nonzero argument. To get a floating point buffer pass a pre-allocated buffer to output_f and NULL to output_i. To get an int16 buffer pass NULL to output_f and a pre-allocated buffer to output_i. Alternatively you can pass NULL to both buffer arguments and the decoder won't render anything.

After reading an audio buffer, the current position in the one stream is advanced. Remember that if you're using percentage seeking you can't call mpeg3_set_sample to rewind and read every channel. How then, do you read more than one channel of audio data? Use

mpeg3_reread_audio(mpeg3_t *file, 
		float *output_f,      /* Pointer to pre-allocated buffer of floats */
		short *output_i,      /* Pointer to pre-allocated buffer of int16's */
		int channel,          /* Channel to decode */
		long samples,         /* Number of samples to decode */
		int stream);
to read each remaining channel after the first channel.

To read video data there are two methods. RGB frames or YUV frames. To get an RGB frame use:

int mpeg3_read_frame(mpeg3_t *file, 
		unsigned char **output_rows, // Array of pointers to the start of each output row
		int in_x,                    // Location in input frame to take picture
		int in_y, 
		int in_w, 
		int in_h, 
		int out_w,                   // Dimensions of output_rows
		int out_h, 
		int color_model,             // One of the color model #defines given above.
		int stream);
The video decoding works like a camcorder taking copies of a movie screen. The decoder "sees" a region of the movie screen defined by in_x, in_y, in_w, in_h and transfers it to the frame buffer defined by **output_rows. The input values must be within the boundaries given by mpeg3_video_width and mpeg3_video_height. The size of the frame buffer is defined by out_w, out_h. Although the input dimensions are constrained, the frame buffer can be any size.

color_model defines which RGB color model the picture should be decoded to and the possible values are given in libmpeg3.h. The frame buffer pointed to by output_rows must have enough memory allocated to store the color model you select.

You must allocate 4 extra bytes in the last output_row. This is scratch area for the MMX routines.

mpeg3_read_frame advances the position in the one stream by 1 frame.

To read YUV frames use one of two methods:

int mpeg3_read_yuvframe(mpeg3_t *file,
		char *y_output,
		char *u_output,
		char *v_output,
		int in_x,
		int in_y,
		int in_w,
		int in_h,
		int stream);
The behavior of in_x, in_y, in_w, in_h is identical to mpeg3_read_frame except here you have no control over the output frame size. You must allocate in_w * in_h for the y_output, and in_w * in_h / 4 for the u_output and v_output. While mpeg3_read_yuvframe allows cropping of letterbox it still requires one memcpy. A faster alternative is:

int mpeg3_read_yuvframe_ptr(mpeg3_t *file,
		char **y_output,
		char **u_output,
		char **v_output,
		int stream);
This redirects a *y_output, *u_output, and *v_output pointer to the scratch buffer that decoding took place in. Since MPEG is temporal compression, there is always a buffer containing the last decoder output.

For professional use the library can decode YUV 4:2:2 video in addition to YUV 4:2:0. This variable is determined at encoding time, won't affect the usage of mpeg3_read_frame but you do need an extra function call in order to use mpeg3_read_yuvframe. To determine the encoding of the video stream use

mpeg3_colormodel(mpeg3_t *file, int stream)
This returns either MPEG3_YUV420P or MPEG3_YUV422P. The output buffers and the YUV to RGB conversion for mpeg3_read_yuvframe must be adjusted for the higher sampling of MPEG3_YUV422P. When using mpeg3_read_yuvframe_ptr you don't need to adjust any output buffers.

Synchronizing video with audio

To synchronize video with audio in realtime you need to sometimes delay the video and sometimes drop frames. It's easy to calculate the number of frames to drop but if you're using percentage seeking you can't calculate the exact percentage to seek forward by. Instead call

mpeg3_drop_frames(mpeg3_t *file, long frames, int stream);

This skips frames frames from the current position whether in percentage seeking or absolute seeking.

STEP 7: Close the file

Be sure to close the file with mpeg3_close(mpeg3_t *file) when you're done with it.

Using tables of contents for editing

In 1985 everyone watched Smurfs but one guy watched Robotech. In 1990 everyone watched Teenage Mutant Ninja Turtles but one guy watched Transformers. In 1995 everyone watched Pokemon but one guy watched Behind the Scenes. Now everyone wants handheld organizers but one guy wants MPEG editors. For the wierdos who always looked at the camera rig instead of the celebrity, libmpeg3 supports a way of seeking to an exact frame or sample in any kind of MPEG encapsulation format for editing.

A table of contents must be built for any footage to be edited with libmpeg3. Run mpeg3toc <mpeg stream> <output table of contents>

For editing DVD footage, the mpeg stream argument should be the ifo file belonging to the title set to be edited. This utility reads through every file comprising the mpeg stream and records the offset of every 65536th sample and every keyframe so it can be pretty slow.

The resulting table of contents file should be passed to mpeg3_open and mpeg3_open_copy just like a normal file. The only difference is frame seeking of video is available.

libmpeg3-1.5.4/ifo.h0000644000175000017500000001471307742725645014415 0ustar enderender00000000000000#ifndef __IFO_H__ #define __IFO_H__ #ifndef DVD_VIDEO_LB_LEN #define DVD_VIDEO_LB_LEN 2048 #endif #define OFFSET_IFO 0x0000 #define OFFSET_VTS 0x0000 #define OFFSET_LEN 0x00C0 #define IFO_OFFSET_TAT 0x00C0 #define OFFSET_VTSI_MAT 0x0080 #define IFO_OFFSET_VIDEO 0x0100 #define IFO_OFFSET_AUDIO 0x0200 #define IFO_OFFSET_SUBPIC 0x0250 // for debug and error output /** * Video Info Table */ typedef struct { #if BYTE_ORDER == BIG_ENDIAN u_char compression : 2; u_char system : 2; u_char ratio : 2; u_char perm_displ : 2; u_char line21_1 : 1; u_char line21_2 : 1; u_char source_res : 2; u_char letterboxed : 1; u_char mode : 1; #else u_char perm_displ : 2; u_char ratio : 2; u_char system : 2; u_char compression : 2; u_char mode : 1; u_char letterboxed : 1; u_char source_res : 2; u_char line21_2 : 1; u_char line21_1 : 1; #endif } ifo_video_info_t; /** * Audio Table */ typedef struct { #if MPEG3_LITTLE_ENDIAN u_char num_channels : 3; // number of channels (n+1) u_char sample_freq : 2; // sampling frequency u_char quantization : 2; // quantization u_char appl_mode2 : 1; // audio application mode u_char appl_mode1 : 1; // u_char type : 2; // audio type (language included?) u_char multichannel_extension: 1; u_char coding_mode : 2; #else u_char appl_mode2 : 1; u_char quantization : 2; u_char sample_freq : 2; u_char num_channels : 3; u_char coding_mode : 2; u_char multichannel_extension: 1; u_char type : 2; u_char appl_mode1 : 1; #endif u_short lang_code : 16; // description u_int foo : 8; // 0x00000000 ? u_int caption : 8; u_int bar : 8; // 0x00000000 ? } ifo_audio_t; #define IFO_AUDIO_LEN 7 /** * Subpicture Table */ typedef struct { u_short prefix : 16; // 0x0100 ? u_short lang_code : 16; // description u_char foo : 8; // dont know u_char caption : 8; // 0x00 ? } ifo_spu_t; /** * Time Map Table header entry */ #if 0 typedef struct { u_char tu : 16; // time unit (in seconds) u_int : 16; // don't know } ifo_tmt_hdr_t; #endif typedef struct { u_int : 24; // don't know u_char tu : 8; // time unit (in seconds) } ifoq_tmt_hdr_t; //#define IFO_TMT_HDR_LEN 4 #define IFOQ_TMT_HDR_LEN 1 /** * hmm */ typedef struct { u_short vob_id : 16; // Video Object Identifier u_char cell_id : 8; // Cell Identifier u_char : 8; // don't know u_int start : 32; // Cell start u_int end : 32; // Cell end } ifo_cell_addr_t; typedef struct { u_short vob_id : 16; // Video Object Identifier u_short cell_id : 16; // Cell Identifier } ifo_pgc_cell_pos_t; /** * Part of Title AND Title set Cell Address */ typedef struct { u_short pgc; // Program Chain (PTT) u_short pg; // Program (PTT) u_long start; // Start of VOBU (VTS? CADDR) u_long end; // End of VOBU (VTS? CADDR) } ifo_ptt_data_t; typedef struct { u_int num; // Number of Chapters ifo_ptt_data_t *data; // Data } ifo_ptt_sub_t; typedef struct { u_int num; // Number of Titles ifo_ptt_sub_t *title; // Titles } ifo_ptt_t; typedef struct { u_char chain_info : 8; // 0x5e 0xde(2 angles, no overlay), 0x5f 0x9f 0x9f 0xdf(4 angles overlay), 0x2 0xa 0x8(1 angle) u_char foo : 8; // parent control ?? u_char still_time : 8; u_char cell_cmd : 8; //u_int foo : 32; u_int len_time : 32; u_int vobu_start : 32; // 1st vobu start u_int ilvu_end : 32; u_int vobu_last_start : 32; u_int vobu_last_end : 32; } ifo_pgci_cell_addr_t; #define PGCI_CELL_ADDR_LEN 24 #define ID_NUM_MENU_VOBS 0 #define ID_NUM_TITLE_VOBS 1 #define ID_MAT 0 #define ID_PTT 1 #define ID_TSP 1 #define ID_TITLE_PGCI 2 #define ID_MENU_PGCI 3 #define ID_TMT 4 #define ID_MENU_CELL_ADDR 5 #define ID_MENU_VOBU_ADDR_MAP 6 #define ID_TITLE_CELL_ADDR 7 #define ID_TITLE_VOBU_ADDR_MAP 8 /** * Information Table - for internal use only */ typedef struct { u_int num_menu_vobs; u_int vob_start; u_char *data[10]; int fd; // file descriptor __off64_t pos; // offset of ifo file on device } ifo_t; /** * Generic header */ #define IFO_HDR_LEN 8 #define IFOQ_HDR_LEN 2 typedef struct { u_short num : 16; // number of entries u_short : 16; // don't known (reserved?) u_int len : 32; // length of table } ifo_hdr_t; typedef struct { u_short : 16; // don't known (reserved?) u_short num : 16; // number of entries u_int len : 32; // length of table } ifoq_hdr_t; /** * Prototypes */ ifo_t *ifoOpen (int fd, __off64_t pos); int ifoClose (ifo_t *ifo); u_int ifoGetVOBStart (ifo_t *ifo); int ifoGetNumberOfTitles (ifo_t *ifo); int ifoGetNumberOfParts (ifo_t *ifo); int ifoGetVMGPTT (ifo_hdr_t *hdr, char **ptr); int ifoGetPGCI (ifo_hdr_t *hdr, int title, char **ptr); int ifoGetCLUT (char *pgc, char **ptr); u_int ifoGetCellPlayInfo (u_char *pgc, u_char **ptr); u_int ifoGetCellPos (u_char *pgc, u_char **ptr); int ifoGetProgramMap (char *pgc, char **ptr); int ifoGetCellAddr (char *cell_addr, char **ptr); int ifoGetCellAddrNum (char *hdr); int ifoGetAudio (char *hdr, char **ptr); int ifoGetSPU (char *hdr, char **ptr); ifo_ptt_t *ifo_get_ptt (ifo_t *ifo); int ifo_get_num_title_pgci (ifo_t *ifo); u_char *ifo_get_ptr_title_pgci (ifo_t *ifo, int index); char *ifoDecodeLang (u_short descr); int ifoIsVTS (ifo_t *ifo); int ifoIsVMG (ifo_t *ifo); void ifoPrintVideo (u_char *ptr); void ifoPrintCellPlayInfo (u_char *ptr, u_int num); void ifoPrintCellInfo (u_char *ptr, u_int num); void ifoPrintCellPos (u_char *ptr, u_int num); void ifoPrintCLUT (u_char *ptr); void ifoPrintProgramMap (u_char *ptr, u_int num); #ifdef PARSER void ifoPrintAudio (ifo_audio_t *ptr, u_int num); void ifoPrintSPU (ifo_spu_t *ptr, u_int num); void ifoPrintTMT (ifo_t *ifo); void ifoPrintVMOP (u_char *opcode); void ifoPrint_ptt (ifo_ptt_t *ptt); void ifoPrint_vts_vobu_addr_map (ifo_t *ifo); void ifoPrint_vtsm_vobu_addr_map (ifo_t *ifo); void ifoPrint_vts_cell_addr (ifo_t *ifo); void ifoPrint_vtsm_cell_addr (ifo_t *ifo); void ifoPrint_title_pgci (ifo_t *ifo); void ifoPrint_pgc_cmd (u_char *pgc_ptr); void ifoPrintTSP (u_char *toast); void ifoPrint_pgc (u_char *ptr); #endif #endif libmpeg3-1.5.4/libmpeg3.c0000644000175000017500000006016410012105052015276 0ustar enderender00000000000000#include "libmpeg3.h" #include "mpeg3private.h" #include "mpeg3protos.h" #include #include #include #define MAX(a, b) ((a) > (b) ? (a) : (b)) int mpeg3_major() { return MPEG3_MAJOR; } int mpeg3_minor() { return MPEG3_MINOR; } int mpeg3_release() { return MPEG3_RELEASE; } mpeg3_t* mpeg3_new(char *path) { int i; mpeg3_t *file = calloc(1, sizeof(mpeg3_t)); file->cpus = 1; file->fs = mpeg3_new_fs(path); // file->have_mmx = mpeg3_mmx_test(); // Late compilers don't produce usable code. file->have_mmx = 0; file->demuxer = mpeg3_new_demuxer(file, 0, 0, -1); file->seekable = 1; return file; } int mpeg3_delete(mpeg3_t *file) { int i; for(i = 0; i < file->total_vstreams; i++) mpeg3_delete_vtrack(file, file->vtrack[i]); for(i = 0; i < file->total_astreams; i++) mpeg3_delete_atrack(file, file->atrack[i]); mpeg3_delete_fs(file->fs); mpeg3_delete_demuxer(file->demuxer); if(file->frame_offsets) { for(i = 0; i < file->total_vstreams; i++) { free(file->frame_offsets[i]); free(file->keyframe_numbers[i]); } free(file->frame_offsets); free(file->keyframe_numbers); free(file->total_frame_offsets); free(file->total_keyframe_numbers); } if(file->sample_offsets) { for(i = 0; i < file->total_astreams; i++) free(file->sample_offsets[i]); free(file->sample_offsets); free(file->total_sample_offsets); } if(file->channel_counts) free(file->channel_counts); free(file); return 0; } int mpeg3_check_sig(char *path) { mpeg3_fs_t *fs; u_int32_t bits; char *ext; int result = 0; fs = mpeg3_new_fs(path); if(mpeg3io_open_file(fs)) { /* File not found */ return 0; } bits = mpeg3io_read_int32(fs); /* Test header */ if(bits == MPEG3_TOC_PREFIX) { result = 1; } else if((((bits >> 24) & 0xff) == MPEG3_SYNC_BYTE) || (bits == MPEG3_PACK_START_CODE) || ((bits & 0xfff00000) == 0xfff00000) || ((bits & 0xffff0000) == 0xffe30000) || (bits == MPEG3_SEQUENCE_START_CODE) || (bits == MPEG3_PICTURE_START_CODE) || (((bits & 0xffff0000) >> 16) == MPEG3_AC3_START_CODE) || ((bits >> 8) == MPEG3_ID3_PREFIX) || (bits == MPEG3_RIFF_CODE) || (bits == MPEG3_IFO_PREFIX)) { result = 1; ext = strrchr(path, '.'); if(ext) { /* Test file extension. */ if(strncasecmp(ext, ".ifo", 4) && strncasecmp(ext, ".mp2", 4) && strncasecmp(ext, ".mp3", 4) && strncasecmp(ext, ".m1v", 4) && strncasecmp(ext, ".m2v", 4) && strncasecmp(ext, ".m2s", 4) && strncasecmp(ext, ".mpg", 4) && strncasecmp(ext, ".vob", 4) && strncasecmp(ext, ".mpeg", 4) && strncasecmp(ext, ".ac3", 4)) result = 0; } } mpeg3io_close_file(fs); mpeg3_delete_fs(fs); return result; } static uint32_t read_int32(unsigned char *buffer, int *position) { uint32_t temp; if(MPEG3_LITTLE_ENDIAN) { ((unsigned char*)&temp)[3] = buffer[(*position)++]; ((unsigned char*)&temp)[2] = buffer[(*position)++]; ((unsigned char*)&temp)[1] = buffer[(*position)++]; ((unsigned char*)&temp)[0] = buffer[(*position)++]; } else { ((unsigned char*)&temp)[0] = buffer[(*position)++]; ((unsigned char*)&temp)[1] = buffer[(*position)++]; ((unsigned char*)&temp)[2] = buffer[(*position)++]; ((unsigned char*)&temp)[3] = buffer[(*position)++]; } return temp; } static uint64_t read_int64(unsigned char *buffer, int *position) { uint64_t temp; if(MPEG3_LITTLE_ENDIAN) { ((unsigned char*)&temp)[7] = buffer[(*position)++]; ((unsigned char*)&temp)[6] = buffer[(*position)++]; ((unsigned char*)&temp)[5] = buffer[(*position)++]; ((unsigned char*)&temp)[4] = buffer[(*position)++]; ((unsigned char*)&temp)[3] = buffer[(*position)++]; ((unsigned char*)&temp)[2] = buffer[(*position)++]; ((unsigned char*)&temp)[1] = buffer[(*position)++]; ((unsigned char*)&temp)[0] = buffer[(*position)++]; } else { ((unsigned char*)&temp)[0] = buffer[(*position)++]; ((unsigned char*)&temp)[1] = buffer[(*position)++]; ((unsigned char*)&temp)[2] = buffer[(*position)++]; ((unsigned char*)&temp)[3] = buffer[(*position)++]; ((unsigned char*)&temp)[4] = buffer[(*position)++]; ((unsigned char*)&temp)[5] = buffer[(*position)++]; ((unsigned char*)&temp)[6] = buffer[(*position)++]; ((unsigned char*)&temp)[7] = buffer[(*position)++]; } return temp; } static int read_toc(mpeg3_t *file, int *atracks_return, int *vtracks_return) { unsigned char *buffer; int file_type; int position = 4; int stream_type; int i, j; int is_vfs = 0; int vfs_len = strlen(RENDERFARM_FS_PREFIX); int toc_version; int64_t current_byte = 0; // Fix title paths for Cinelerra VFS if(!strncmp(file->fs->path, RENDERFARM_FS_PREFIX, vfs_len)) is_vfs = 1; buffer = malloc(mpeg3io_total_bytes(file->fs)); mpeg3io_seek(file->fs, 0); mpeg3io_read_data(buffer, mpeg3io_total_bytes(file->fs), file->fs); // Test version if((toc_version = buffer[position++]) != MPEG3_TOC_VERSION) { fprintf(stderr, "read_toc: invalid TOC version %x\n", toc_version); return 1; } //printf("read_toc %lld\n", mpeg3io_total_bytes(file->fs)); // File type file_type = buffer[position++]; switch(file_type) { case FILE_TYPE_PROGRAM: file->is_program_stream = 1; break; case FILE_TYPE_TRANSPORT: file->is_transport_stream = 1; break; case FILE_TYPE_AUDIO: file->is_audio_stream = 1; break; case FILE_TYPE_VIDEO: file->is_video_stream = 1; break; } //printf("read_toc 10\n"); // Stream ID's while((stream_type = buffer[position]) != TITLE_PATH) { int offset; int stream_id; //printf("read_toc %d %x\n", position, buffer[position]); position++; offset = read_int32(buffer, &position); stream_id = read_int32(buffer, &position); if(stream_type == STREAM_AUDIO) { file->demuxer->astream_table[offset] = stream_id; } if(stream_type == STREAM_VIDEO) { file->demuxer->vstream_table[offset] = stream_id; } } //printf("read_toc 10\n"); // Titles while(buffer[position] == TITLE_PATH) { char string[MPEG3_STRLEN]; int string_len = 0; mpeg3_title_t *title; FILE *test_fd; // Construct title path from VFS prefix and path. position++; if(is_vfs) { strcpy(string, RENDERFARM_FS_PREFIX); string_len = vfs_len; } while(buffer[position] != 0) string[string_len++] = buffer[position++]; string[string_len++] = 0; position++; // Test title availability test_fd = fopen(string, "r"); if(test_fd) { fclose(test_fd); } else { // Try concatenating title and toc directory if title is not absolute and // toc path has a directory section. if((!is_vfs && string[0] != '/') || (is_vfs && string[vfs_len] != '/')) { // Get toc filename without path char *ptr = strrchr(file->fs->path, '/'); if(ptr) { char string2[MPEG3_STRLEN]; // Stack filename on toc path strcpy(string2, file->fs->path); if(!is_vfs) strcpy(&string2[ptr - file->fs->path + 1], string); else strcpy(&string2[ptr - file->fs->path + 1], string + vfs_len); test_fd = fopen(string2, "r"); if(test_fd) { fclose(test_fd); strcpy(string, string2); } else { fprintf(stderr, "read_toc: failed to open %s or %s\n", string, string2); return 1; } } else { fprintf(stderr, "read_toc: failed to open %s\n", string); return 1; } } else { fprintf(stderr, "read_toc: failed to open %s\n", string); return 1; } } title = file->demuxer->titles[file->demuxer->total_titles++] = mpeg3_new_title(file, string); title->total_bytes = read_int64(buffer, &position); title->start_byte = current_byte; title->end_byte = title->start_byte + title->total_bytes; current_byte = title->end_byte; // Cells title->cell_table_size = title->cell_table_allocation = read_int32(buffer, &position); title->cell_table = calloc(title->cell_table_size, sizeof(mpeg3demux_cell_t)); for(i = 0; i < title->cell_table_size; i++) { title->cell_table[i].start_byte = read_int64(buffer, &position); title->cell_table[i].end_byte = read_int64(buffer, &position); title->cell_table[i].program = read_int32(buffer, &position); } } //printf("read_toc 10\n"); // Audio streams // Skip ATRACK_COUNT position++; *atracks_return = read_int32(buffer, &position); //printf("read_toc 10\n"); // Skip VTRACK_COUNT position++; *vtracks_return = read_int32(buffer, &position); //printf("read_toc 10\n"); if(*atracks_return) { file->channel_counts = calloc(sizeof(int), *atracks_return); file->sample_offsets = malloc(sizeof(int64_t*) * *atracks_return); file->total_sample_offsets = malloc(sizeof(int*) * *atracks_return); for(i = 0; i < *atracks_return; i++) { file->channel_counts[i] = read_int32(buffer, &position); file->total_sample_offsets[i] = read_int32(buffer, &position); file->sample_offsets[i] = malloc(file->total_sample_offsets[i] * sizeof(int64_t)); for(j = 0; j < file->total_sample_offsets[i]; j++) { file->sample_offsets[i][j] = read_int64(buffer, &position); //printf("samples %llx\n", file->sample_offsets[i][j]); } } } //printf("read_toc 10\n"); if(*vtracks_return) { file->frame_offsets = malloc(sizeof(int64_t*) * *vtracks_return); file->total_frame_offsets = malloc(sizeof(int*) * *vtracks_return); file->keyframe_numbers = malloc(sizeof(int64_t*) * *vtracks_return); file->total_keyframe_numbers = malloc(sizeof(int*) * *vtracks_return); for(i = 0; i < *vtracks_return; i++) { file->total_frame_offsets[i] = read_int32(buffer, &position); file->frame_offsets[i] = malloc(file->total_frame_offsets[i] * sizeof(int64_t)); for(j = 0; j < file->total_frame_offsets[i]; j++) { file->frame_offsets[i][j] = read_int64(buffer, &position); //printf("frame %llx\n", file->frame_offsets[i][j]); } file->total_keyframe_numbers[i] = read_int32(buffer, &position); file->keyframe_numbers[i] = malloc(file->total_keyframe_numbers[i] * sizeof(int64_t)); for(j = 0; j < file->total_keyframe_numbers[i]; j++) { file->keyframe_numbers[i][j] = read_int64(buffer, &position); } } } //printf("read_toc 10\n"); free(buffer); //printf("read_toc 10\n"); //printf("read_toc 1\n"); mpeg3demux_open_title(file->demuxer, 0); //printf("read_toc 10\n"); //printf("read_toc 2 %llx\n", mpeg3demux_tell(file->demuxer)); return 0; } mpeg3_t* mpeg3_open_copy(char *path, mpeg3_t *old_file) { mpeg3_t *file = 0; unsigned int bits; int i, done; /* The table of contents may have fewer tracks than are in the demuxer */ /* This limits the track count */ int toc_atracks = 0x7fffffff; int toc_vtracks = 0x7fffffff; /* Initialize the file structure */ file = mpeg3_new(path); //printf("mpeg3_open_copy 1 %s\n", path); /* Need to perform authentication before reading a single byte. */ if(mpeg3io_open_file(file->fs)) { mpeg3_delete(file); return 0; } /* =============================== Create the title objects ========================= */ bits = mpeg3io_read_int32(file->fs); //printf("mpeg3_open 1 %p %d %d %d %d\n", old_file, file->is_transport_stream, file->is_program_stream, file->is_video_stream, file->is_audio_stream); if(bits == MPEG3_TOC_PREFIX) /* TOC */ { /* Table of contents for another title set */ if(!old_file) { if(read_toc(file, &toc_atracks, &toc_vtracks)) { mpeg3io_close_file(file->fs); mpeg3_delete(file); return 0; } } mpeg3io_close_file(file->fs); } else // IFO file if(bits == MPEG3_IFO_PREFIX) { if(!old_file) { if(mpeg3_read_ifo(file, 0)) { mpeg3_delete(file); mpeg3io_close_file(file->fs); return 0; } } file->is_ifo_file = 1; mpeg3io_close_file(file->fs); } else if(((bits >> 24) & 0xff) == MPEG3_SYNC_BYTE) { /* Transport stream */ file->is_transport_stream = 1; } else if(bits == MPEG3_PACK_START_CODE) { /* Program stream */ /* Determine packet size empirically */ file->is_program_stream = 1; } else if((bits & 0xfff00000) == 0xfff00000 || (bits & 0xffff0000) == 0xffe30000 || ((bits >> 8) == MPEG3_ID3_PREFIX) || (bits == MPEG3_RIFF_CODE)) { /* MPEG Audio only */ file->is_audio_stream = 1; } else if(bits == MPEG3_SEQUENCE_START_CODE || bits == MPEG3_PICTURE_START_CODE) { /* Video only */ file->is_video_stream = 1; } else if(((bits & 0xffff0000) >> 16) == MPEG3_AC3_START_CODE) { /* AC3 Audio only */ file->is_audio_stream = 1; } else { mpeg3_delete(file); fprintf(stderr, "mpeg3_open: not an MPEG 2 stream\n"); return 0; } /* * printf("mpeg3_open 2 %p %d %d %d %d\n", * old_file, * file->is_transport_stream, * file->is_program_stream, * file->is_video_stream, * file->is_audio_stream); */ // Configure packet size if(file->is_transport_stream) file->packet_size = MPEG3_TS_PACKET_SIZE; else if(file->is_program_stream) file->packet_size = 0; else if(file->is_audio_stream) file->packet_size = MPEG3_DVD_PACKET_SIZE; else if(file->is_video_stream) file->packet_size = MPEG3_DVD_PACKET_SIZE; //printf("mpeg3_open 1\n"); /* Create titles */ /* Copy timecodes from an old demuxer */ if(old_file && mpeg3_get_demuxer(old_file)) { mpeg3demux_copy_titles(file->demuxer, mpeg3_get_demuxer(old_file)); file->is_transport_stream = old_file->is_transport_stream; file->is_program_stream = old_file->is_program_stream; } else /* Start from scratch */ if(!file->demuxer->total_titles) { mpeg3demux_create_title(file->demuxer, 0, 0); } //printf("mpeg3_open 50\n"); /* Generate tracks */ if(file->is_transport_stream || file->is_program_stream) { /* Create video tracks */ for(i = 0; i < MPEG3_MAX_STREAMS && file->total_vstreams < toc_vtracks; i++) { if(file->demuxer->vstream_table[i]) { file->vtrack[file->total_vstreams] = mpeg3_new_vtrack(file, i, file->demuxer, file->total_vstreams); if(file->vtrack[file->total_vstreams]) file->total_vstreams++; } } /* Create audio tracks */ for(i = 0; i < MPEG3_MAX_STREAMS && file->total_astreams < toc_atracks; i++) { if(file->demuxer->astream_table[i]) { file->atrack[file->total_astreams] = mpeg3_new_atrack(file, i, file->demuxer->astream_table[i], file->demuxer, file->total_astreams); if(file->atrack[file->total_astreams]) file->total_astreams++; } } } else if(file->is_video_stream) { /* Create video tracks */ file->vtrack[0] = mpeg3_new_vtrack(file, -1, file->demuxer, 0); if(file->vtrack[0]) file->total_vstreams++; } else if(file->is_audio_stream) { /* Create audio tracks */ file->atrack[0] = mpeg3_new_atrack(file, -1, AUDIO_UNKNOWN, file->demuxer, 0); if(file->atrack[0]) file->total_astreams++; } mpeg3io_close_file(file->fs); return file; } mpeg3_t* mpeg3_open(char *path) { return mpeg3_open_copy(path, 0); } int mpeg3_close(mpeg3_t *file) { /* File is closed in the same procedure it is opened in. */ mpeg3_delete(file); return 0; } int mpeg3_set_cpus(mpeg3_t *file, int cpus) { int i; file->cpus = cpus; for(i = 0; i < file->total_vstreams; i++) mpeg3video_set_cpus(file->vtrack[i]->video, cpus); return 0; } int mpeg3_set_mmx(mpeg3_t *file, int use_mmx) { int i; file->have_mmx = use_mmx; for(i = 0; i < file->total_vstreams; i++) mpeg3video_set_mmx(file->vtrack[i]->video, use_mmx); return 0; } int mpeg3_has_audio(mpeg3_t *file) { return file->total_astreams > 0; } int mpeg3_total_astreams(mpeg3_t *file) { return file->total_astreams; } int mpeg3_audio_channels(mpeg3_t *file, int stream) { if(file->total_astreams) return file->atrack[stream]->channels; return -1; } int mpeg3_sample_rate(mpeg3_t *file, int stream) { if(file->total_astreams) return file->atrack[stream]->sample_rate; return -1; } long mpeg3_get_sample(mpeg3_t *file, int stream) { if(file->total_astreams) return file->atrack[stream]->current_position; return -1; } int mpeg3_set_sample(mpeg3_t *file, long sample, int stream) { if(file->total_astreams) { //printf(__FUNCTION__ " 1 %d %d\n", file->atrack[stream]->current_position, sample); file->atrack[stream]->current_position = sample; mpeg3audio_seek_sample(file->atrack[stream]->audio, sample); return 0; } return -1; } long mpeg3_audio_samples(mpeg3_t *file, int stream) { if(file->total_astreams) return file->atrack[stream]->total_samples; return -1; } char* mpeg3_audio_format(mpeg3_t *file, int stream) { if(stream < file->total_astreams) { switch(file->atrack[stream]->format) { case AUDIO_UNKNOWN: return "Unknown"; break; case AUDIO_MPEG: return "MPEG"; break; case AUDIO_AC3: return "AC3"; break; case AUDIO_PCM: return "PCM"; break; case AUDIO_AAC: return "AAC"; break; case AUDIO_JESUS: return "Vorbis"; break; } } return ""; } int mpeg3_has_video(mpeg3_t *file) { return file->total_vstreams > 0; } int mpeg3_total_vstreams(mpeg3_t *file) { return file->total_vstreams; } int mpeg3_video_width(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->width; return -1; } int mpeg3_video_height(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->height; return -1; } float mpeg3_aspect_ratio(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->aspect_ratio; return 0; } double mpeg3_frame_rate(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->frame_rate; return -1; } long mpeg3_video_frames(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->total_frames; return -1; } long mpeg3_get_frame(mpeg3_t *file, int stream) { if(file->total_vstreams) return file->vtrack[stream]->current_position; return -1; } int mpeg3_set_frame(mpeg3_t *file, long frame, int stream) { if(file->total_vstreams) { file->vtrack[stream]->current_position = frame; mpeg3video_seek_frame(file->vtrack[stream]->video, frame); return 0; } return -1; } int mpeg3_seek_byte(mpeg3_t *file, int64_t byte) { int i; // file->percentage_pts = -1; for(i = 0; i < file->total_vstreams; i++) { file->vtrack[i]->current_position = 0; mpeg3video_seek_byte(file->vtrack[i]->video, byte); } for(i = 0; i < file->total_astreams; i++) { file->atrack[i]->current_position = 0; mpeg3audio_seek_byte(file->atrack[i]->audio, byte); } return 0; } /* * double mpeg3_get_percentage_pts(mpeg3_t *file) * { * return file->percentage_pts; * } * * void mpeg3_set_percentage_pts(mpeg3_t *file, double pts) * { * } */ int mpeg3_previous_frame(mpeg3_t *file, int stream) { file->last_type_read = 2; file->last_stream_read = stream; if(file->total_vstreams) return mpeg3video_previous_frame(file->vtrack[stream]->video); return 0; } int64_t mpeg3_tell_byte(mpeg3_t *file) { int64_t result = 0; if(file->last_type_read == 1) { result = mpeg3demux_tell_byte(file->atrack[file->last_stream_read]->demuxer); } if(file->last_type_read == 2) { result = mpeg3demux_tell_byte(file->vtrack[file->last_stream_read]->demuxer); } return result; } int64_t mpeg3_get_bytes(mpeg3_t *file) { return mpeg3demux_movie_size(file->demuxer); } double mpeg3_get_time(mpeg3_t *file) { double atime = 0, vtime = 0; if(file->is_transport_stream || file->is_program_stream) { /* Timecode only available in transport stream */ if(file->last_type_read == 1) { atime = mpeg3demux_get_time(file->atrack[file->last_stream_read]->demuxer); } else if(file->last_type_read == 2) { vtime = mpeg3demux_get_time(file->vtrack[file->last_stream_read]->demuxer); } } else { /* Use percentage and total time */ if(file->total_astreams) { atime = mpeg3demux_tell_byte(file->atrack[0]->demuxer) * mpeg3_audio_samples(file, 0) / mpeg3_sample_rate(file, 0) / mpeg3_get_bytes(file); } if(file->total_vstreams) { vtime = mpeg3demux_tell_byte(file->vtrack[0]->demuxer) * mpeg3_video_frames(file, 0) / mpeg3_frame_rate(file, 0) / mpeg3_get_bytes(file); } } return MAX(atime, vtime); } int mpeg3_end_of_audio(mpeg3_t *file, int stream) { int result = 0; if(!file->atrack[stream]->channels) return 1; result = mpeg3demux_eof(file->atrack[stream]->demuxer); return result; } int mpeg3_end_of_video(mpeg3_t *file, int stream) { int result = 0; result = mpeg3demux_eof(file->vtrack[stream]->demuxer); return result; } int mpeg3_drop_frames(mpeg3_t *file, long frames, int stream) { int result = -1; if(file->total_vstreams) { result = mpeg3video_drop_frames(file->vtrack[stream]->video, frames); if(frames > 0) file->vtrack[stream]->current_position += frames; file->last_type_read = 2; file->last_stream_read = stream; } return result; } int mpeg3_colormodel(mpeg3_t *file, int stream) { if(file->total_vstreams) { return mpeg3video_colormodel(file->vtrack[stream]->video); } return 0; } int mpeg3_set_rowspan(mpeg3_t *file, int bytes, int stream) { if(file->total_vstreams) { file->vtrack[stream]->video->row_span = bytes; } return 0; } int mpeg3_read_frame(mpeg3_t *file, unsigned char **output_rows, int in_x, int in_y, int in_w, int in_h, int out_w, int out_h, int color_model, int stream) { int result = -1; //printf("mpeg3_read_frame 1 %d\n", file->vtrack[stream]->current_position); if(file->total_vstreams) { result = mpeg3video_read_frame(file->vtrack[stream]->video, file->vtrack[stream]->current_position, output_rows, in_x, in_y, in_w, in_h, out_w, out_h, color_model); //printf(__FUNCTION__ " 2\n"); file->last_type_read = 2; file->last_stream_read = stream; file->vtrack[stream]->current_position++; } //printf("mpeg3_read_frame 2 %d\n", file->vtrack[stream]->current_position); return result; } int mpeg3_read_yuvframe(mpeg3_t *file, char *y_output, char *u_output, char *v_output, int in_x, int in_y, int in_w, int in_h, int stream) { int result = -1; //printf("mpeg3_read_yuvframe 1\n"); if(file->total_vstreams) { result = mpeg3video_read_yuvframe(file->vtrack[stream]->video, file->vtrack[stream]->current_position, y_output, u_output, v_output, in_x, in_y, in_w, in_h); file->last_type_read = 2; file->last_stream_read = stream; file->vtrack[stream]->current_position++; } //printf("mpeg3_read_yuvframe 100\n"); return result; } int mpeg3_read_yuvframe_ptr(mpeg3_t *file, char **y_output, char **u_output, char **v_output, int stream) { int result = -1; if(file->total_vstreams) { result = mpeg3video_read_yuvframe_ptr(file->vtrack[stream]->video, file->vtrack[stream]->current_position, y_output, u_output, v_output); file->last_type_read = 2; file->last_stream_read = stream; file->vtrack[stream]->current_position++; } return result; } int mpeg3_read_audio(mpeg3_t *file, float *output_f, short *output_i, int channel, long samples, int stream) { int result = -1; if(file->total_astreams) { result = mpeg3audio_decode_audio(file->atrack[stream]->audio, output_f, output_i, channel, samples); file->last_type_read = 1; file->last_stream_read = stream; file->atrack[stream]->current_position += samples; } return result; } int mpeg3_reread_audio(mpeg3_t *file, float *output_f, short *output_i, int channel, long samples, int stream) { if(file->total_astreams) { mpeg3_set_sample(file, file->atrack[stream]->current_position - samples, stream); file->last_type_read = 1; file->last_stream_read = stream; return mpeg3_read_audio(file, output_f, output_i, channel, samples, stream); } return -1; } int mpeg3_read_audio_chunk(mpeg3_t *file, unsigned char *output, long *size, long max_size, int stream) { int result = 0; if(file->total_astreams) { result = mpeg3audio_read_raw(file->atrack[stream]->audio, output, size, max_size); file->last_type_read = 1; file->last_stream_read = stream; } return result; } int mpeg3_read_video_chunk(mpeg3_t *file, unsigned char *output, long *size, long max_size, int stream) { int result = 0; if(file->total_vstreams) { result = mpeg3video_read_raw(file->vtrack[stream]->video, output, size, max_size); file->last_type_read = 2; file->last_stream_read = stream; } return result; } libmpeg3-1.5.4/libmpeg3.h0000644000175000017500000001560007742725645015336 0ustar enderender00000000000000#ifndef LIBMPEG3_H #define LIBMPEG3_H #ifdef __cplusplus extern "C" { #endif #include "mpeg3private.h" /* Supported color models for mpeg3_read_frame */ #define MPEG3_RGB565 2 #define MPEG3_BGR888 0 #define MPEG3_BGRA8888 1 #define MPEG3_RGB888 3 #define MPEG3_RGBA8888 4 #define MPEG3_RGBA16161616 5 /* Color models for the 601 to RGB conversion */ /* 601 not implemented for scalar code */ #define MPEG3_601_RGB565 11 #define MPEG3_601_BGR888 7 #define MPEG3_601_BGRA8888 8 #define MPEG3_601_RGB888 9 #define MPEG3_601_RGBA8888 10 /* Supported color models for mpeg3_read_yuvframe */ #define MPEG3_YUV420P 12 #define MPEG3_YUV422P 13 /* Get version information */ int mpeg3_major(); int mpeg3_minor(); int mpeg3_release(); /* Check for file compatibility. Return 1 if compatible. */ int mpeg3_check_sig(char *path); /* Open the MPEG3 stream. */ mpeg3_t* mpeg3_open(char *path); /* Open the MPEG3 stream and copy the tables from an already open stream. */ /* Eliminates the initial timecode search. */ mpeg3_t* mpeg3_open_copy(char *path, mpeg3_t *old_file); int mpeg3_close(mpeg3_t *file); /* Performance */ int mpeg3_set_cpus(mpeg3_t *file, int cpus); int mpeg3_set_mmx(mpeg3_t *file, int use_mmx); /* Query the MPEG3 stream about audio. */ int mpeg3_has_audio(mpeg3_t *file); int mpeg3_total_astreams(mpeg3_t *file); /* Number of multiplexed audio streams */ int mpeg3_audio_channels(mpeg3_t *file, int stream); int mpeg3_sample_rate(mpeg3_t *file, int stream); char* mpeg3_audio_format(mpeg3_t *file, int stream); /* Total length obtained from the timecode. */ /* For DVD files, this is unreliable. */ long mpeg3_audio_samples(mpeg3_t *file, int stream); int mpeg3_set_sample(mpeg3_t *file, long sample, int stream); /* Seek to a sample */ long mpeg3_get_sample(mpeg3_t *file, int stream); /* Tell current position */ /* Read a PCM buffer of audio from 1 channel and advance the position. */ /* Return a 1 if error. */ /* Stream defines the number of the multiplexed stream to read. */ /* If both output arguments are null the audio is not rendered. */ int mpeg3_read_audio(mpeg3_t *file, float *output_f, /* Pointer to pre-allocated buffer of floats */ short *output_i, /* Pointer to pre-allocated buffer of int16's */ int channel, /* Channel to decode */ long samples, /* Number of samples to decode */ int stream); /* Stream containing the channel */ /* Reread the last PCM buffer from a different channel and advance the position */ int mpeg3_reread_audio(mpeg3_t *file, float *output_f, /* Pointer to pre-allocated buffer of floats */ short *output_i, /* Pointer to pre-allocated buffer of int16's */ int channel, /* Channel to decode */ long samples, /* Number of samples to decode */ int stream); /* Stream containing the channel */ /* Read the next compressed audio chunk. Store the size in size and return a */ /* 1 if error. */ /* Stream defines the number of the multiplexed stream to read. */ int mpeg3_read_audio_chunk(mpeg3_t *file, unsigned char *output, long *size, long max_size, int stream); /* Query the stream about video. */ int mpeg3_has_video(mpeg3_t *file); int mpeg3_total_vstreams(mpeg3_t *file); /* Number of multiplexed video streams */ int mpeg3_video_width(mpeg3_t *file, int stream); int mpeg3_video_height(mpeg3_t *file, int stream); float mpeg3_aspect_ratio(mpeg3_t *file, int stream); /* aspect ratio. 0 if none */ double mpeg3_frame_rate(mpeg3_t *file, int stream); /* Frames/sec */ /* Total length. */ /* This is meaningless except for TOC files. */ long mpeg3_video_frames(mpeg3_t *file, int stream); int mpeg3_set_frame(mpeg3_t *file, long frame, int stream); /* Seek to a frame */ int mpeg3_skip_frames(); long mpeg3_get_frame(mpeg3_t *file, int stream); /* Tell current position */ /* Total bytes. Used for absolute byte seeking. */ int64_t mpeg3_get_bytes(mpeg3_t *file); /* Seek all the tracks to the absolute byte in the */ /* file. This eliminates the need for tocs but doesn't */ /* give frame accuracy. */ int mpeg3_seek_byte(mpeg3_t *file, int64_t byte); int64_t mpeg3_tell_byte(mpeg3_t *file); /* To synchronize audio and video in percentage seeking mode, these must */ /* be called after percentage seeking the video file and before */ /* percentage seeking the audio file. Then when the audio file is percentage */ /* seeked it will search for the nearest pts to file->percentage_pts. */ /* * double mpeg3_get_percentage_pts(mpeg3_t *file); * void mpeg3_set_percentage_pts(mpeg3_t *file, double pts); */ int mpeg3_previous_frame(mpeg3_t *file, int stream); int mpeg3_end_of_audio(mpeg3_t *file, int stream); int mpeg3_end_of_video(mpeg3_t *file, int stream); /* Give the seconds time in the last packet read */ double mpeg3_get_time(mpeg3_t *file); /* Read a frame. The dimensions of the input area and output frame must be supplied. */ /* The frame is taken from the input area and scaled to fit the output frame in 1 step. */ /* Stream defines the number of the multiplexed stream to read. */ /* The last row of **output_rows must contain 4 extra bytes for scratch work. */ int mpeg3_read_frame(mpeg3_t *file, unsigned char **output_rows, /* Array of pointers to the start of each output row */ int in_x, /* Location in input frame to take picture */ int in_y, int in_w, int in_h, int out_w, /* Dimensions of output_rows */ int out_h, int color_model, /* One of the color model #defines */ int stream); /* Get the colormodel being used natively by the stream */ int mpeg3_colormodel(mpeg3_t *file, int stream); /* Set the row stride to be used in mpeg3_read_yuvframe */ int mpeg3_set_rowspan(mpeg3_t *file, int bytes, int stream); /* Read a frame in the native color model used by the stream. */ /* The Y, U, and V planes are copied into the y, u, and v */ /* buffers provided. */ /* The input is cropped to the dimensions given but not scaled. */ int mpeg3_read_yuvframe(mpeg3_t *file, char *y_output, char *u_output, char *v_output, int in_x, int in_y, int in_w, int in_h, int stream); /* Read a frame in the native color model used by the stream. */ /* The Y, U, and V planes are not copied but the _output pointers */ /* are redirected to the frame buffer. */ int mpeg3_read_yuvframe_ptr(mpeg3_t *file, char **y_output, char **u_output, char **v_output, int stream); /* Drop frames number of frames */ int mpeg3_drop_frames(mpeg3_t *file, long frames, int stream); /* Read the next compressed frame including headers. */ /* Store the size in size and return a 1 if error. */ /* Stream defines the number of the multiplexed stream to read. */ int mpeg3_read_video_chunk(mpeg3_t *file, unsigned char *output, long *size, long max_size, int stream); /* Master control */ int mpeg3_total_programs(); int mpeg3_set_program(int program); #ifdef __cplusplus } #endif #endif libmpeg3-1.5.4/Makefile0000644000175000017500000001353607747706776015142 0ustar enderender00000000000000CC = gcc NASM = nasm USE_MMX = 0 USE_CSS = 1 A52DIR := $(shell expr a52dec* ) ifeq ($(origin CFLAGS), environment) HAVE_CFLAGS := y else HAVE_CFLAGS := n endif OBJDIR := $(shell uname --machine) ifeq ($(OBJDIR), alpha) USE_MMX = 0 ifneq ($(HAVE_CFLAGS), y) CFLAGS := -O4 -arch ev67 -ieee -accept c99_keywords -gcc_messages endif endif ifeq ($(OBJDIR), i686) USE_MMX = 1 ifneq ($(HAVE_CFLAGS), y) CFLAGS := -O2 -fomit-frame-pointer -falign-loops=2 -falign-jumps=2 -falign-functions=2 -I/usr/local/include endif CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE endif ifeq ($(OBJDIR), x86_64) ifneq ($(HAVE_CFLAGS), y) CFLAGS := -O2 -fomit-frame-pointer -I/usr/local/include endif CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE endif ifeq ($(USE_CSS), 1) CFLAGS += -DHAVE_CSS endif ifeq ($(USE_MMX), 1) CFLAGS += -DHAVE_MMX ASMOBJS = $(OBJDIR)/video/mmxidct.o NASMOBJS = $(OBJDIR)/video/reconmmx.o endif CFLAGS += \ -I. \ -I$(A52DIR)/include \ -I$(A52DIR)/liba52 #CFLAGS += -g OBJS = \ $(OBJDIR)/audio/ac3.o \ $(OBJDIR)/audio/dct.o \ $(OBJDIR)/audio/huffman.o \ $(OBJDIR)/audio/layer2.o \ $(OBJDIR)/audio/layer3.o \ $(OBJDIR)/audio/mpeg3audio.o \ $(OBJDIR)/audio/pcm.o \ $(OBJDIR)/audio/synthesizers.o \ $(OBJDIR)/audio/tables.o \ $(OBJDIR)/bitstream.o \ $(OBJDIR)/libmpeg3.o \ $(OBJDIR)/mpeg3atrack.o \ $(OBJDIR)/mpeg3css.o \ $(OBJDIR)/mpeg3demux.o \ $(OBJDIR)/mpeg3ifo.o \ $(OBJDIR)/mpeg3io.o \ $(OBJDIR)/mpeg3title.o \ $(OBJDIR)/mpeg3vtrack.o \ $(OBJDIR)/video/getpicture.o \ $(OBJDIR)/video/headers.o \ $(OBJDIR)/video/idct.o \ $(OBJDIR)/video/macroblocks.o \ $(OBJDIR)/video/mmxtest.o \ $(OBJDIR)/video/motion.o \ $(OBJDIR)/video/mpeg3video.o \ $(OBJDIR)/video/output.o \ $(OBJDIR)/video/reconstruct.o \ $(OBJDIR)/video/seek.o \ $(OBJDIR)/video/slice.o \ $(OBJDIR)/video/vlc.o \ $(OBJDIR)/workarounds.o #OBJS = \ # $(OBJDIR)/audio/ac3.o \ # $(OBJDIR)/audio/bit_allocation.o \ # $(OBJDIR)/audio/exponents.o \ # $(OBJDIR)/audio/header.o \ # $(OBJDIR)/audio/huffman.o \ # $(OBJDIR)/audio/layer2.o \ # $(OBJDIR)/audio/layer3.o \ # $(OBJDIR)/audio/mantissa.o \ # $(OBJDIR)/audio/pcm.o \ # $(OBJDIR)/audio/tables.o \ DIRS := \ $(OBJDIR)/audio \ $(OBJDIR)/video include Makefile.a52 DIRS += $(A52DIRS) OUTPUT = $(OBJDIR)/libmpeg3.a UTILS = $(OBJDIR)/mpeg3dump $(OBJDIR)/mpeg3toc $(OBJDIR)/mpeg3cat #$(OBJDIR)/mpeg3split LIBS = -lm -lpthread $(shell if ! test -d $(OBJDIR) \; then mkdir -p $(OBJDIR) \; fi ) $(shell echo $(CFLAGS) > $(OBJDIR)/c_flags) $(shell echo $(A52CFLAGS) > $(OBJDIR)/a52_flags) $(shell echo $(OBJS) $(ASMOBJS) $(A52OBJS) $(NASMOBJS) > $(OBJDIR)/objs) $(shell mkdir -p $(DIRS) ) all: $(OUTPUT) $(UTILS) $(OUTPUT): $(OBJS) $(ASMOBJS) $(NASMOBJS) $(A52OBJS) ar rcs $(OUTPUT) `cat $(OBJDIR)/objs` $(OBJDIR)/mpeg3dump: $(OUTPUT) mpeg3dump.c $(CC) `cat $(OBJDIR)/c_flags` -o $(OBJDIR)/mpeg3dump mpeg3dump.c $(OUTPUT) $(LIBS) $(OBJDIR)/mpeg3toc: $(OUTPUT) mpeg3toc.c $(CC) `cat $(OBJDIR)/c_flags` -o $(OBJDIR)/mpeg3toc mpeg3toc.c $(OUTPUT) $(LIBS) $(OBJDIR)/mpeg3cat: $(OUTPUT) mpeg3cat.c $(CC) `cat $(OBJDIR)/c_flags` -o $(OBJDIR)/mpeg3cat mpeg3cat.c $(OUTPUT) $(LIBS) #$(OBJDIR)/mpeg3split: $(OUTPUT) # $(CC) `cat $(OBJDIR)/c_flags` -o $(OBJDIR)/mpeg3split mpeg3split.c $(OUTPUT) $(LIBS) $(OBJDIR)/mpeg2qt: $(OUTPUT) $(CC) `cat $(OBJDIR)/c_flags` -o $(OBJDIR)/mpeg2qt mpeg2qt.c \ $(OUTPUT) \ $(LIBS) \ -I. \ -I../quicktime \ ../quicktime/$(OBJDIR)/libquicktime.a \ -lpng \ -lz \ -ldl install: cp $(UTILS) /usr/bin clean: rm -rf $(OBJDIR) backup: clean cd .. && \ tar zcf libmpeg3.tar.gz libmpeg3 wc: cat *.c *.h audio/*.c audio/*.h video/*.c video/*.h | wc $(OBJS): $(CC) -c `cat $(OBJDIR)/c_flags` $(subst $(OBJDIR)/,, $*.c) -o $*.o $(ASMOBJS): $(CC) -c `cat $(OBJDIR)/c_flags` $(subst $(OBJDIR)/,, $*.S) -o $*.o $(NASMOBJS): $(NASM) -f elf $(subst $(OBJDIR)/,, $*.s) -o $*.o $(A52OBJS): $(CC) -c `cat $(OBJDIR)/a52_flags` $(subst $(OBJDIR)/,, $*.c) -o $*.o $(OBJDIR)/bitstream.o: bitstream.c $(OBJDIR)/mpeg3dump.o: mpeg3dump.c $(OBJDIR)/libmpeg3.o: libmpeg3.c $(OBJDIR)/mpeg3atrack.o: mpeg3atrack.c $(OBJDIR)/mpeg3css.o: mpeg3css.c $(OBJDIR)/mpeg3demux.o: mpeg3demux.c $(OBJDIR)/mpeg3ifo.o: mpeg3ifo.c $(OBJDIR)/mpeg3io.o: mpeg3io.c #$(OBJDIR)/mpeg3split.o: mpeg3split.c $(OBJDIR)/mpeg3title.o: mpeg3title.c $(OBJDIR)/mpeg3toc.o: mpeg3toc.c $(OBJDIR)/mpeg3toc3.o: mpeg3toc3.c $(OBJDIR)/mpeg3vtrack.o: mpeg3vtrack.c $(OBJDIR)/audio/ac3.o: audio/ac3.c $(OBJDIR)/audio/bit_allocation.o: audio/bit_allocation.c $(OBJDIR)/audio/dct.o: audio/dct.c $(OBJDIR)/audio/exponents.o: audio/exponents.c $(OBJDIR)/audio/header.o: audio/header.c $(OBJDIR)/audio/huffman.o: audio/huffman.c $(OBJDIR)/audio/layer2.o: audio/layer2.c $(OBJDIR)/audio/layer3.o: audio/layer3.c $(OBJDIR)/audio/mantissa.o: audio/mantissa.c $(OBJDIR)/audio/mpeg3audio.o: audio/mpeg3audio.c $(OBJDIR)/audio/pcm.o: audio/pcm.c $(OBJDIR)/audio/synthesizers.o: audio/synthesizers.c $(OBJDIR)/audio/tables.o: audio/tables.c $(OBJDIR)/video/getpicture.o: video/getpicture.c $(OBJDIR)/video/headers.o: video/headers.c $(OBJDIR)/video/idct.o: video/idct.c $(OBJDIR)/video/macroblocks.o: video/macroblocks.c $(OBJDIR)/video/mmxtest.o: video/mmxtest.c $(OBJDIR)/video/motion.o: video/motion.c $(OBJDIR)/video/mpeg3video.o: video/mpeg3video.c $(OBJDIR)/video/output.o: video/output.c $(OBJDIR)/video/reconstruct.o: video/reconstruct.c $(OBJDIR)/video/seek.o: video/seek.c $(OBJDIR)/video/slice.o: video/slice.c $(OBJDIR)/video/vlc.o: video/vlc.c $(OBJDIR)/workarounds.o: workarounds.c include depend.a52 libmpeg3-1.5.4/Makefile.a520000644000175000017500000000174307742725645015514 0ustar enderender00000000000000A52DIR := $(shell expr a52dec* ) A52DIRS := \ $(OBJDIR)/$(A52DIR)/liba52/ \ $(OBJDIR)/$(A52DIR)/libao/ \ $(OBJDIR)/$(A52DIR)/src/ \ $(OBJDIR)/$(A52DIR)/test/ A52OBJS := \ $(OBJDIR)/$(A52DIR)/liba52/bit_allocate.o \ $(OBJDIR)/$(A52DIR)/liba52/bitstream.o \ $(OBJDIR)/$(A52DIR)/liba52/downmix.o \ $(OBJDIR)/$(A52DIR)/liba52/imdct.o \ $(OBJDIR)/$(A52DIR)/liba52/parse.o \ $(OBJDIR)/$(A52DIR)/libao/audio_out_float.o \ $(OBJDIR)/$(A52DIR)/libao/audio_out_null.o \ $(OBJDIR)/$(A52DIR)/libao/audio_out.o \ $(OBJDIR)/$(A52DIR)/libao/audio_out_oss.o \ $(OBJDIR)/$(A52DIR)/libao/audio_out_solaris.o \ $(OBJDIR)/$(A52DIR)/libao/audio_out_wav.o \ $(OBJDIR)/$(A52DIR)/libao/float2s16.o \ $(OBJDIR)/$(A52DIR)/src/a52dec.o \ $(OBJDIR)/$(A52DIR)/src/extract_a52.o \ $(OBJDIR)/$(A52DIR)/src/getopt.o \ $(OBJDIR)/$(A52DIR)/test/compare.o A52CFLAGS = \ $(CFLAGS) \ -DHAVE_CONFIG_H \ -I$(A52DIR)/ \ -I$(A52DIR)/include \ -I$(A52DIR)/liba52 \ -I$(A52DIR)/libao \ -I$(A52DIR)/src libmpeg3-1.5.4/make_package0000755000175000017500000000027307742725645016001 0ustar enderender00000000000000#!/bin/sh VERSION=1.4 rm -r /tmp/libmpeg3-$VERSION mkdir -p /tmp/libmpeg3-$VERSION make clean cp -rd * /tmp/libmpeg3-$VERSION cd /tmp tar zcf libmpeg3-$VERSION.tar.gz libmpeg3-$VERSION libmpeg3-1.5.4/make_rpm0000755000175000017500000000027507742725645015206 0ustar enderender00000000000000#!/bin/sh VERSION=1.2.2 rm -r /tmp/libmpeg3-$VERSION mkdir -p /tmp/libmpeg3-$VERSION make clean cp -rd * /tmp/libmpeg3-$VERSION cd /tmp tar zcf libmpeg3-$VERSION.tar.gz libmpeg3-$VERSION libmpeg3-1.5.4/mpeg2qt.c0000644000175000017500000001241107742725645015203 0ustar enderender00000000000000#include #include #include "colormodels.h" #include "libmpeg3.h" #include "quicktime.h" #define OUTPUT_PATH "movie.mov" //#define VIDEO_CODEC QUICKTIME_DIVX #define VIDEO_CODEC QUICKTIME_JPEG //#define VIDEO_CODEC QUICKTIME_YUV420 #define AUDIO_CODEC QUICKTIME_TWOS //#define AUDIO_CODEC QUICKTIME_VORBIS // Hack for libdv to remove glib dependancy void g_log (const char *log_domain, int log_level, const char *format, ...) { } void g_logv (const char *log_domain, int log_level, const char *format, ...) { } // Hack for XFree86 4.1.0 int atexit(void (*function)(void)) { return 0; } // Dump mpeg video to a quicktime movie quicktime_t *output; mpeg3_t *input; pthread_mutex_t mutex; int predicate = 0; void* trap_interrupt() { pthread_mutex_lock(&mutex); if(!predicate) { predicate = 1; printf("interrupt trapped 1\n"); quicktime_close(output); printf("interrupt trapped 2\n"); exit(0); // Can't join any threads in the mpeg library which may have been interrupted // before unblocking. // mpeg3_close(input); } } int main(int argc, char *argv[]) { int frame_count = -1; char *row_pointers[3]; int do_audio = 0; int do_video = 0; int channels = 0; long afragment = 65536; float **audio_output; int layer = 0; int astream = 0; char input_path[1024]; char output_path[1024]; int i; long current_frame = 0; long current_sample = 0; pthread_mutex_init(&mutex, NULL); signal(SIGINT, trap_interrupt); input_path[0] = 0; output_path[0] = 0; if(argc < 3) { printf("Usage: %s [-a] [-v] [frame count]\n", argv[0]); exit(1); } for(i = 1; i < argc; i++) { if(!strcmp(argv[i], "-a")) { do_audio = 1; } else if(!strcmp(argv[i], "-v")) { do_video = 1; } else if(!input_path[0]) { strcpy(input_path, argv[i]); } else if(!output_path[0]) { strcpy(output_path, argv[i]); } else frame_count = atol(argv[i]); } //printf("main 1\n"); if(!(input = mpeg3_open(input_path))) { exit(1); } //printf("main 1\n"); if(!(output = quicktime_open(output_path, 0, 1))) { exit(1); } //printf("main 1\n"); if(do_video) { if(!mpeg3_total_vstreams(input)) { do_video = 0; } else { quicktime_set_video(output, 1, mpeg3_video_width(input, layer), mpeg3_video_height(input, layer), mpeg3_frame_rate(input, layer), VIDEO_CODEC); quicktime_set_jpeg(output, 80, 0); } } //printf("main 1\n"); if(do_audio) { if(!mpeg3_total_astreams(input)) { do_audio = 0; } else { int i; channels = mpeg3_audio_channels(input, astream); quicktime_set_audio(output, channels, mpeg3_sample_rate(input, 0), 24, AUDIO_CODEC); audio_output = malloc(sizeof(float*) * channels); for(i = 0; i < channels; i++) audio_output[i] = malloc(sizeof(float) * afragment); } } //printf("main 1\n"); // quicktime_set_jpeg(output, 100, 0); mpeg3_set_mmx(input, 0); while((!(do_video && mpeg3_end_of_video(input, layer)) || !(do_audio && mpeg3_end_of_audio(input, astream))) && (current_frame < frame_count || frame_count < 0)) { //printf("%d %d\n", mpeg3_end_of_video(input, layer), mpeg3_end_of_audio(input, astream)); if(do_audio) { if(!mpeg3_end_of_audio(input, astream)) { int fragment = afragment; int i, j, k; i = astream; k = 0; for(j = 0; j < mpeg3_audio_channels(input, i); j++, k++) { if(j == 0) mpeg3_read_audio(input, audio_output[k], /* Pointer to pre-allocated buffer of floats */ 0, /* Pointer to pre-allocated buffer of int16's */ j, /* Channel to decode */ fragment, /* Number of samples to decode */ i); else mpeg3_reread_audio(input, audio_output[k], /* Pointer to pre-allocated buffer of floats */ 0, /* Pointer to pre-allocated buffer of int16's */ j, /* Channel to decode */ fragment, /* Number of samples to decode */ i); } quicktime_encode_audio(output, 0, audio_output, fragment); current_sample += fragment; if(!do_video) { printf(" %d samples written\r", current_sample); fflush(stdout); } } else current_sample += afragment; } if(do_video) { if(!mpeg3_end_of_video(input, layer)) { int fragment; if(do_audio) fragment = (long)((double)current_sample / mpeg3_sample_rate(input, 0) * mpeg3_frame_rate(input, layer) - current_frame); else fragment = 1; for(i = 0; i < fragment && !mpeg3_end_of_video(input, layer); i++) { mpeg3_read_yuvframe_ptr(input, &row_pointers[0], &row_pointers[1], &row_pointers[2], layer); switch(mpeg3_colormodel(input, layer)) { case MPEG3_YUV420P: quicktime_set_cmodel(output, BC_YUV420P); break; case MPEG3_YUV422P: quicktime_set_cmodel(output, BC_YUV422P); break; } quicktime_encode_video(output, (unsigned char **)row_pointers, 0); current_frame++; printf(" %d frames written\r", current_frame); fflush(stdout); } } } } printf("main 2\n"); printf("\n"); quicktime_close(output); mpeg3_close(input); } libmpeg3-1.5.4/mpeg3atrack.c0000644000175000017500000000223107742725645016024 0ustar enderender00000000000000#include "libmpeg3.h" #include "mpeg3protos.h" #include mpeg3_atrack_t* mpeg3_new_atrack(mpeg3_t *file, int stream_id, int format, mpeg3_demuxer_t *demuxer, int number) { mpeg3_atrack_t *new_atrack; new_atrack = calloc(1, sizeof(mpeg3_atrack_t)); if(file->channel_counts) new_atrack->channels = file->channel_counts[number]; new_atrack->sample_rate = 0; new_atrack->total_samples = 0; new_atrack->demuxer = mpeg3_new_demuxer(file, 1, 0, stream_id); if(new_atrack->demuxer) mpeg3demux_copy_titles(new_atrack->demuxer, demuxer); new_atrack->current_position = 0; /* Copy pointers */ if(file->sample_offsets) { new_atrack->sample_offsets = file->sample_offsets[number]; new_atrack->total_sample_offsets = file->total_sample_offsets[number]; } new_atrack->audio = mpeg3audio_new(file, new_atrack, format); if(!new_atrack->audio) { /* Failed */ mpeg3_delete_atrack(file, new_atrack); new_atrack = 0; } return new_atrack; } int mpeg3_delete_atrack(mpeg3_t *file, mpeg3_atrack_t *atrack) { if(atrack->audio) mpeg3audio_delete(atrack->audio); if(atrack->demuxer) mpeg3_delete_demuxer(atrack->demuxer); free(atrack); return 0; } libmpeg3-1.5.4/mpeg3atrack.h0000644000175000017500000000015307742725645016032 0ustar enderender00000000000000#ifndef MPEG3ATRACK_H #define MPEG3ATRACK_H #include "mpeg3demux.h" #include "audio/mpeg3audio.h" #endif libmpeg3-1.5.4/mpeg3cat.c0000644000175000017500000002232607743175167015334 0ustar enderender00000000000000/* Concatenate elementary streams */ /* Mpeg3cat is useful for extracting elementary streams from program streams. */ #include "libmpeg3.h" #include "mpeg3protos.h" #include #include #include #include #define MPEG3_SEQUENCE_START_CODE 0x000001b3 #define BUFFER_SIZE 1000000 int main(int argc, char *argv[]) { char inpath[1024], outpath[1024], newpath[1024]; mpeg3_t *in; FILE *out; int out_counter = 0; int current_file, current_output_file = 0, i; unsigned int bits; unsigned char *buffer; long output_size; int result = 0; long total_frames = 0; int do_audio = 0, do_video = 0; int stream = 0; int64_t total_written = 0; if(argc < 2) { fprintf(stderr, "Concatenate elementary streams or demultiplex a program stream.\n" "Usage: mpeg3cat -[av0123456789] [infile...] > \n\n" "Example: Concatenate 2 video files: mpeg3cat xena1.m2v xena2.m2v > xena.m2v\n" " Extract audio stream 0: mpeg3cat -a0 xena.vob > war_cry.ac3\n"); exit(1); } outpath[0] = 0; for(i = 1; i < argc; i++) { if(argv[i][0] == '-') { if(argv[i][1] != 'a' && argv[i][1] != 'v' && argv[i][1] != 'o') { fprintf(stderr, "invalid option %s\n", argv[i]); exit(1); } else if(argv[i][1] == 'o') { // Check for filename if(i < argc - 1) { strcpy(outpath, argv[++i]); } else { fprintf(stderr, "-o requires an output file\n"); exit(1); } // Check if file exists if(out = fopen(outpath, "r")) { fprintf(stderr, "%s exists.\n", outpath); exit(1); } } else { if(argv[i][1] == 'a') do_audio = 1; else if(argv[i][1] == 'v') do_video = 1; if(argv[i][2] != 0) { stream = argv[i][2] - 48; } } } } buffer = malloc(BUFFER_SIZE); if(outpath[0]) { if(!(out = fopen(outpath, "wb"))) { fprintf(stderr, "Failed to open %s for writing\n", outpath); exit(1); } } else out = stdout; for(current_file = 1; current_file < argc; current_file++) { if(argv[current_file][0] == '-') continue; strcpy(inpath, argv[current_file]); if(!(in = mpeg3_open(inpath))) { fprintf(stderr, "Skipping %s\n", inpath); continue; } //fprintf(stderr, "%d %d %d %d\n", in->is_transport_stream, in->is_program_stream, in->is_audio_stream, in->is_video_stream); if((mpeg3_has_audio(in) && in->is_audio_stream) || (do_audio && !in->is_audio_stream && !in->is_video_stream)) { do_audio = 1; /* Add audio stream to end */ mpeg3demux_seek_byte(in->atrack[stream]->demuxer, 0); // mpeg3bits_refill(in->atrack[stream]->audio->astream); while(!mpeg3_read_audio_chunk(in, buffer, &output_size, BUFFER_SIZE, stream)) { result = !fwrite(buffer, output_size, 1, out); if(result) { perror("fwrite audio chunk"); break; } } } else if((mpeg3_has_video(in) && in->is_video_stream) || (do_video && !in->is_video_stream && !in->is_audio_stream)) { /* Add video stream to end */ int hour, minute, second, frame; long gop_frame; unsigned long code; float carry; int i, offset; mpeg3demux_seek_byte(in->vtrack[stream]->demuxer, 0); mpeg3bits_refill(in->vtrack[stream]->video->vstream); do_video = 1; while(!mpeg3_read_video_chunk(in, buffer, &output_size, BUFFER_SIZE, stream) && output_size >= 4) { code = (unsigned long)buffer[output_size - 4] << 24; code |= (unsigned long)buffer[output_size - 3] << 16; code |= (unsigned long)buffer[output_size - 2] << 8; code |= (unsigned long)buffer[output_size - 1]; /* Got a frame at the end of this buffer. */ if(code == MPEG3_PICTURE_START_CODE) { total_frames++; } else if(code == MPEG3_SEQUENCE_END_CODE) { /* Got a sequence end code at the end of this buffer. */ output_size -= 4; } code = (unsigned long)buffer[0] << 24; code |= (unsigned long)buffer[1] << 16; code |= (unsigned long)buffer[2] << 8; code |= buffer[3]; i = 0; offset = 0; if(code == MPEG3_SEQUENCE_START_CODE && current_output_file > 0) { /* Skip the sequence start code */ i += 4; while(i < output_size && code != MPEG3_GOP_START_CODE) { code <<= 8; code |= buffer[i++]; } i -= 4; offset = i; } /* Search for GOP header to fix */ code = (unsigned long)buffer[i++] << 24; code |= (unsigned long)buffer[i++] << 16; code |= (unsigned long)buffer[i++] << 8; code |= buffer[i++]; while(i < output_size && code != MPEG3_GOP_START_CODE) { code <<= 8; code |= buffer[i++]; } if(code == MPEG3_GOP_START_CODE) { /* Get the time code */ code = (unsigned long)buffer[i] << 24; code |= (unsigned long)buffer[i + 1] << 16; code |= (unsigned long)buffer[i + 2] << 8; code |= (unsigned long)buffer[i + 3]; hour = code >> 26 & 0x1f; minute = code >> 20 & 0x3f; second = code >> 13 & 0x3f; frame = code >> 7 & 0x3f; gop_frame = (long)(hour * 3600 * mpeg3_frame_rate(in, stream) + minute * 60 * mpeg3_frame_rate(in, stream) + second * mpeg3_frame_rate(in, stream) + frame); /* fprintf(stderr, "old: %02d:%02d:%02d:%02d ", hour, minute, second, frame); */ /* Write a new time code */ hour = (long)((float)(total_frames - 1) / mpeg3_frame_rate(in, stream) / 3600); carry = hour * 3600 * mpeg3_frame_rate(in, stream); minute = (long)((float)(total_frames - 1 - carry) / mpeg3_frame_rate(in, stream) / 60); carry += minute * 60 * mpeg3_frame_rate(in, stream); second = (long)((float)(total_frames - 1 - carry) / mpeg3_frame_rate(in, stream)); carry += second * mpeg3_frame_rate(in, stream); frame = (total_frames - 1 - carry); buffer[i] = ((code >> 24) & 0x80) | (hour << 2) | (minute >> 4); buffer[i + 1] = ((code >> 16) & 0x08) | ((minute & 0xf) << 4) | (second >> 3); buffer[i + 2] = ((second & 0x7) << 5) | (frame >> 1); buffer[i + 3] = (code & 0x7f) | ((frame & 0x1) << 7); /* fprintf(stderr, "new: %02d:%02d:%02d:%02d\n", hour, minute, second, frame); */ } /* Test 32 bit overflow */ if(outpath[0]) { if(ftell(out) > 0x7f000000) { fclose(out); out_counter++; sprintf(newpath, "%s%03d", outpath, out_counter); if(!(out = fopen(newpath, "wb"))) { fprintf(stderr, "Couldn't open %s for writing.\n", newpath); exit(1); } } } /* * fprintf(stderr, "mpeg3cat 5 %02x %02x %02x %02x\n", * (buffer + offset)[0], * (buffer + offset)[1], * (buffer + offset)[2], * (buffer + offset)[3]); */ /* Write the frame */ result = !fwrite(buffer + offset, output_size - offset, 1, out); if(result) { perror("fwrite video chunk"); break; } } } else if(in->is_program_stream) { mpeg3_demuxer_t *demuxer = in->vtrack[0]->demuxer; result = 0; //fprintf(stderr, "mpeg3cat 1\n"); /* Append program stream with no changes */ demuxer->read_all = 1; mpeg3demux_seek_byte(demuxer, 0); while(!result) { result = mpeg3_advance_cell(demuxer, 0); //fprintf(stderr, "mpeg3cat 1 %d\n", result); if(!result) { result = mpeg3demux_read_program(demuxer); if(result) fprintf(stderr, "Hit end of data in %s\n", inpath); } // Decrypt it if(!result) { long decryption_offset = demuxer->last_packet_decryption - demuxer->last_packet_start; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; mpeg3io_seek(title->fs, demuxer->last_packet_start); demuxer->raw_size = demuxer->last_packet_end - demuxer->last_packet_start; //fprintf(stderr, "mpeg3cat 2 %d %x\n", decryption_offset, demuxer->raw_data[decryption_offset]); /* * if(demuxer->raw_size != 0x800) * fprintf(stderr, __FUNCTION__ " %llx", demuxer->last_packet_start); */ mpeg3io_read_data(demuxer->raw_data, demuxer->raw_size, title->fs); if(decryption_offset > 0 && demuxer->raw_data[decryption_offset] & 0x30) { //fprintf(stderr, "mpeg3cat 3\n"); if(mpeg3_decrypt_packet(title->fs->css, demuxer->raw_data, 0)) { fprintf(stderr, "get_ps_pes_packet: Decryption not available\n"); return 1; } //fprintf(stderr, "mpeg3cat 4\n"); demuxer->raw_data[decryption_offset] &= 0xcf; } } //printf("mpeg3cat 3 %d\n", result); // Write it if(!result) { result = !fwrite(demuxer->raw_data, demuxer->raw_size, 1, out); total_written += demuxer->raw_size; if(result) fprintf(stderr, "%s\n", strerror(errno)); } //fprintf(stderr, "%llx %llx\n", mpeg3demux_tell(demuxer), mpeg3demux_tell(demuxer) - total_written); } } else { fprintf(stderr, "Unsupported stream type.\n"); mpeg3_close(in); in = 0; continue; } mpeg3_close(in); in = 0; current_output_file++; } /* Terminate output */ if(current_output_file > 0 && do_video) { /*fprintf(stderr, "\n"); */ /* Write new end of sequence */ buffer[0] = MPEG3_SEQUENCE_END_CODE >> 24; buffer[1] = (MPEG3_SEQUENCE_END_CODE >> 16) & 0xff; buffer[2] = (MPEG3_SEQUENCE_END_CODE >> 8) & 0xff; buffer[3] = MPEG3_SEQUENCE_END_CODE & 0xff; result = !fwrite(buffer, 4, 1, out); } if(outpath[0]) fclose(out); exit(0); } libmpeg3-1.5.4/mpeg3css.c0000644000175000017500000010200310026623571015325 0ustar enderender00000000000000/* * Copyright (C) 2000 Derek Fawcus et. al. * Ported to libmpeg3 by et. al. * * This code may be used under the terms of Version 2 of the GPL, * read the file COPYING for details. * */ /* * These routines do some reordering of the supplied data before * calling engine() to do the main work. * * The reordering seems similar to that done by the initial stages of * the DES algorithm, in that it looks like it's just been done to * try and make software decoding slower. I'm not sure that it * actually adds anything to the security. * * The nature of the shuffling is that the bits of the supplied * parameter 'varient' are reorganised (and some inverted), and * the bytes of the parameter 'challenge' are reorganised. * * The reorganisation in each routine is different, and the first * (CryptKey1) does not bother of play with the 'varient' parameter. * * Since this code is only run once per disk change, I've made the * code table driven in order to improve readability. * * Since these routines are so similar to each other, one could even * abstract them all to one routine supplied a parameter determining * the nature of the reordering it has to do. */ #ifdef HAVE_CSS #include "mpeg3css.h" #include "mpeg3private.h" #include #include #include #include #include #include #include #include #include #ifndef FIBMAP #define FIBMAP _IO(0x00,1) /* bmap access */ //#define FIBMAP 1 #endif /* =================================== TABLES ================================ */ static unsigned char mpeg3css_varients[] = { 0xB7, 0x74, 0x85, 0xD0, 0xCC, 0xDB, 0xCA, 0x73, 0x03, 0xFE, 0x31, 0x03, 0x52, 0xE0, 0xB7, 0x42, 0x63, 0x16, 0xF2, 0x2A, 0x79, 0x52, 0xFF, 0x1B, 0x7A, 0x11, 0xCA, 0x1A, 0x9B, 0x40, 0xAD, 0x01 }; static unsigned char mpeg3css_secret[] = {0x55, 0xD6, 0xC4, 0xC5, 0x28}; static unsigned char mpeg3css_table0[] = { 0xB7, 0xF4, 0x82, 0x57, 0xDA, 0x4D, 0xDB, 0xE2, 0x2F, 0x52, 0x1A, 0xA8, 0x68, 0x5A, 0x8A, 0xFF, 0xFB, 0x0E, 0x6D, 0x35, 0xF7, 0x5C, 0x76, 0x12, 0xCE, 0x25, 0x79, 0x29, 0x39, 0x62, 0x08, 0x24, 0xA5, 0x85, 0x7B, 0x56, 0x01, 0x23, 0x68, 0xCF, 0x0A, 0xE2, 0x5A, 0xED, 0x3D, 0x59, 0xB0, 0xA9, 0xB0, 0x2C, 0xF2, 0xB8, 0xEF, 0x32, 0xA9, 0x40, 0x80, 0x71, 0xAF, 0x1E, 0xDE, 0x8F, 0x58, 0x88, 0xB8, 0x3A, 0xD0, 0xFC, 0xC4, 0x1E, 0xB5, 0xA0, 0xBB, 0x3B, 0x0F, 0x01, 0x7E, 0x1F, 0x9F, 0xD9, 0xAA, 0xB8, 0x3D, 0x9D, 0x74, 0x1E, 0x25, 0xDB, 0x37, 0x56, 0x8F, 0x16, 0xBA, 0x49, 0x2B, 0xAC, 0xD0, 0xBD, 0x95, 0x20, 0xBE, 0x7A, 0x28, 0xD0, 0x51, 0x64, 0x63, 0x1C, 0x7F, 0x66, 0x10, 0xBB, 0xC4, 0x56, 0x1A, 0x04, 0x6E, 0x0A, 0xEC, 0x9C, 0xD6, 0xE8, 0x9A, 0x7A, 0xCF, 0x8C, 0xDB, 0xB1, 0xEF, 0x71, 0xDE, 0x31, 0xFF, 0x54, 0x3E, 0x5E, 0x07, 0x69, 0x96, 0xB0, 0xCF, 0xDD, 0x9E, 0x47, 0xC7, 0x96, 0x8F, 0xE4, 0x2B, 0x59, 0xC6, 0xEE, 0xB9, 0x86, 0x9A, 0x64, 0x84, 0x72, 0xE2, 0x5B, 0xA2, 0x96, 0x58, 0x99, 0x50, 0x03, 0xF5, 0x38, 0x4D, 0x02, 0x7D, 0xE7, 0x7D, 0x75, 0xA7, 0xB8, 0x67, 0x87, 0x84, 0x3F, 0x1D, 0x11, 0xE5, 0xFC, 0x1E, 0xD3, 0x83, 0x16, 0xA5, 0x29, 0xF6, 0xC7, 0x15, 0x61, 0x29, 0x1A, 0x43, 0x4F, 0x9B, 0xAF, 0xC5, 0x87, 0x34, 0x6C, 0x0F, 0x3B, 0xA8, 0x1D, 0x45, 0x58, 0x25, 0xDC, 0xA8, 0xA3, 0x3B, 0xD1, 0x79, 0x1B, 0x48, 0xF2, 0xE9, 0x93, 0x1F, 0xFC, 0xDB, 0x2A, 0x90, 0xA9, 0x8A, 0x3D, 0x39, 0x18, 0xA3, 0x8E, 0x58, 0x6C, 0xE0, 0x12, 0xBB, 0x25, 0xCD, 0x71, 0x22, 0xA2, 0x64, 0xC6, 0xE7, 0xFB, 0xAD, 0x94, 0x77, 0x04, 0x9A, 0x39, 0xCF, 0x7C }; static unsigned char mpeg3css_table1[] = { 0x8C, 0x47, 0xB0, 0xE1, 0xEB, 0xFC, 0xEB, 0x56, 0x10, 0xE5, 0x2C, 0x1A, 0x5D, 0xEF, 0xBE, 0x4F, 0x08, 0x75, 0x97, 0x4B, 0x0E, 0x25, 0x8E, 0x6E, 0x39, 0x5A, 0x87, 0x53, 0xC4, 0x1F, 0xF4, 0x5C, 0x4E, 0xE6, 0x99, 0x30, 0xE0, 0x42, 0x88, 0xAB, 0xE5, 0x85, 0xBC, 0x8F, 0xD8, 0x3C, 0x54, 0xC9, 0x53, 0x47, 0x18, 0xD6, 0x06, 0x5B, 0x41, 0x2C, 0x67, 0x1E, 0x41, 0x74, 0x33, 0xE2, 0xB4, 0xE0, 0x23, 0x29, 0x42, 0xEA, 0x55, 0x0F, 0x25, 0xB4, 0x24, 0x2C, 0x99, 0x13, 0xEB, 0x0A, 0x0B, 0xC9, 0xF9, 0x63, 0x67, 0x43, 0x2D, 0xC7, 0x7D, 0x07, 0x60, 0x89, 0xD1, 0xCC, 0xE7, 0x94, 0x77, 0x74, 0x9B, 0x7E, 0xD7, 0xE6, 0xFF, 0xBB, 0x68, 0x14, 0x1E, 0xA3, 0x25, 0xDE, 0x3A, 0xA3, 0x54, 0x7B, 0x87, 0x9D, 0x50, 0xCA, 0x27, 0xC3, 0xA4, 0x50, 0x91, 0x27, 0xD4, 0xB0, 0x82, 0x41, 0x97, 0x79, 0x94, 0x82, 0xAC, 0xC7, 0x8E, 0xA5, 0x4E, 0xAA, 0x78, 0x9E, 0xE0, 0x42, 0xBA, 0x28, 0xEA, 0xB7, 0x74, 0xAD, 0x35, 0xDA, 0x92, 0x60, 0x7E, 0xD2, 0x0E, 0xB9, 0x24, 0x5E, 0x39, 0x4F, 0x5E, 0x63, 0x09, 0xB5, 0xFA, 0xBF, 0xF1, 0x22, 0x55, 0x1C, 0xE2, 0x25, 0xDB, 0xC5, 0xD8, 0x50, 0x03, 0x98, 0xC4, 0xAC, 0x2E, 0x11, 0xB4, 0x38, 0x4D, 0xD0, 0xB9, 0xFC, 0x2D, 0x3C, 0x08, 0x04, 0x5A, 0xEF, 0xCE, 0x32, 0xFB, 0x4C, 0x92, 0x1E, 0x4B, 0xFB, 0x1A, 0xD0, 0xE2, 0x3E, 0xDA, 0x6E, 0x7C, 0x4D, 0x56, 0xC3, 0x3F, 0x42, 0xB1, 0x3A, 0x23, 0x4D, 0x6E, 0x84, 0x56, 0x68, 0xF4, 0x0E, 0x03, 0x64, 0xD0, 0xA9, 0x92, 0x2F, 0x8B, 0xBC, 0x39, 0x9C, 0xAC, 0x09, 0x5E, 0xEE, 0xE5, 0x97, 0xBF, 0xA5, 0xCE, 0xFA, 0x28, 0x2C, 0x6D, 0x4F, 0xEF, 0x77, 0xAA, 0x1B, 0x79, 0x8E, 0x97, 0xB4, 0xC3, 0xF4 }; static unsigned char mpeg3css_table2[] = { 0xB7, 0x75, 0x81, 0xD5, 0xDC, 0xCA, 0xDE, 0x66, 0x23, 0xDF, 0x15, 0x26, 0x62, 0xD1, 0x83, 0x77, 0xE3, 0x97, 0x76, 0xAF, 0xE9, 0xC3, 0x6B, 0x8E, 0xDA, 0xB0, 0x6E, 0xBF, 0x2B, 0xF1, 0x19, 0xB4, 0x95, 0x34, 0x48, 0xE4, 0x37, 0x94, 0x5D, 0x7B, 0x36, 0x5F, 0x65, 0x53, 0x07, 0xE2, 0x89, 0x11, 0x98, 0x85, 0xD9, 0x12, 0xC1, 0x9D, 0x84, 0xEC, 0xA4, 0xD4, 0x88, 0xB8, 0xFC, 0x2C, 0x79, 0x28, 0xD8, 0xDB, 0xB3, 0x1E, 0xA2, 0xF9, 0xD0, 0x44, 0xD7, 0xD6, 0x60, 0xEF, 0x14, 0xF4, 0xF6, 0x31, 0xD2, 0x41, 0x46, 0x67, 0x0A, 0xE1, 0x58, 0x27, 0x43, 0xA3, 0xF8, 0xE0, 0xC8, 0xBA, 0x5A, 0x5C, 0x80, 0x6C, 0xC6, 0xF2, 0xE8, 0xAD, 0x7D, 0x04, 0x0D, 0xB9, 0x3C, 0xC2, 0x25, 0xBD, 0x49, 0x63, 0x8C, 0x9F, 0x51, 0xCE, 0x20, 0xC5, 0xA1, 0x50, 0x92, 0x2D, 0xDD, 0xBC, 0x8D, 0x4F, 0x9A, 0x71, 0x2F, 0x30, 0x1D, 0x73, 0x39, 0x13, 0xFB, 0x1A, 0xCB, 0x24, 0x59, 0xFE, 0x05, 0x96, 0x57, 0x0F, 0x1F, 0xCF, 0x54, 0xBE, 0xF5, 0x06, 0x1B, 0xB2, 0x6D, 0xD3, 0x4D, 0x32, 0x56, 0x21, 0x33, 0x0B, 0x52, 0xE7, 0xAB, 0xEB, 0xA6, 0x74, 0x00, 0x4C, 0xB1, 0x7F, 0x82, 0x99, 0x87, 0x0E, 0x5E, 0xC0, 0x8F, 0xEE, 0x6F, 0x55, 0xF3, 0x7E, 0x08, 0x90, 0xFA, 0xB6, 0x64, 0x70, 0x47, 0x4A, 0x17, 0xA7, 0xB5, 0x40, 0x8A, 0x38, 0xE5, 0x68, 0x3E, 0x8B, 0x69, 0xAA, 0x9B, 0x42, 0xA5, 0x10, 0x01, 0x35, 0xFD, 0x61, 0x9E, 0xE6, 0x16, 0x9C, 0x86, 0xED, 0xCD, 0x2E, 0xFF, 0xC4, 0x5B, 0xA0, 0xAE, 0xCC, 0x4B, 0x3B, 0x03, 0xBB, 0x1C, 0x2A, 0xAC, 0x0C, 0x3F, 0x93, 0xC7, 0x72, 0x7A, 0x09, 0x22, 0x3D, 0x45, 0x78, 0xA9, 0xA8, 0xEA, 0xC9, 0x6A, 0xF7, 0x29, 0x91, 0xF0, 0x02, 0x18, 0x3A, 0x4E, 0x7C }; static unsigned char mpeg3css_table3[] = { 0x73, 0x51, 0x95, 0xE1, 0x12, 0xE4, 0xC0, 0x58, 0xEE, 0xF2, 0x08, 0x1B, 0xA9, 0xFA, 0x98, 0x4C, 0xA7, 0x33, 0xE2, 0x1B, 0xA7, 0x6D, 0xF5, 0x30, 0x97, 0x1D, 0xF3, 0x02, 0x60, 0x5A, 0x82, 0x0F, 0x91, 0xD0, 0x9C, 0x10, 0x39, 0x7A, 0x83, 0x85, 0x3B, 0xB2, 0xB8, 0xAE, 0x0C, 0x09, 0x52, 0xEA, 0x1C, 0xE1, 0x8D, 0x66, 0x4F, 0xF3, 0xDA, 0x92, 0x29, 0xB9, 0xD5, 0xC5, 0x77, 0x47, 0x22, 0x53, 0x14, 0xF7, 0xAF, 0x22, 0x64, 0xDF, 0xC6, 0x72, 0x12, 0xF3, 0x75, 0xDA, 0xD7, 0xD7, 0xE5, 0x02, 0x9E, 0xED, 0xDA, 0xDB, 0x4C, 0x47, 0xCE, 0x91, 0x06, 0x06, 0x6D, 0x55, 0x8B, 0x19, 0xC9, 0xEF, 0x8C, 0x80, 0x1A, 0x0E, 0xEE, 0x4B, 0xAB, 0xF2, 0x08, 0x5C, 0xE9, 0x37, 0x26, 0x5E, 0x9A, 0x90, 0x00, 0xF3, 0x0D, 0xB2, 0xA6, 0xA3, 0xF7, 0x26, 0x17, 0x48, 0x88, 0xC9, 0x0E, 0x2C, 0xC9, 0x02, 0xE7, 0x18, 0x05, 0x4B, 0xF3, 0x39, 0xE1, 0x20, 0x02, 0x0D, 0x40, 0xC7, 0xCA, 0xB9, 0x48, 0x30, 0x57, 0x67, 0xCC, 0x06, 0xBF, 0xAC, 0x81, 0x08, 0x24, 0x7A, 0xD4, 0x8B, 0x19, 0x8E, 0xAC, 0xB4, 0x5A, 0x0F, 0x73, 0x13, 0xAC, 0x9E, 0xDA, 0xB6, 0xB8, 0x96, 0x5B, 0x60, 0x88, 0xE1, 0x81, 0x3F, 0x07, 0x86, 0x37, 0x2D, 0x79, 0x14, 0x52, 0xEA, 0x73, 0xDF, 0x3D, 0x09, 0xC8, 0x25, 0x48, 0xD8, 0x75, 0x60, 0x9A, 0x08, 0x27, 0x4A, 0x2C, 0xB9, 0xA8, 0x8B, 0x8A, 0x73, 0x62, 0x37, 0x16, 0x02, 0xBD, 0xC1, 0x0E, 0x56, 0x54, 0x3E, 0x14, 0x5F, 0x8C, 0x8F, 0x6E, 0x75, 0x1C, 0x07, 0x39, 0x7B, 0x4B, 0xDB, 0xD3, 0x4B, 0x1E, 0xC8, 0x7E, 0xFE, 0x3E, 0x72, 0x16, 0x83, 0x7D, 0xEE, 0xF5, 0xCA, 0xC5, 0x18, 0xF9, 0xD8, 0x68, 0xAB, 0x38, 0x85, 0xA8, 0xF0, 0xA1, 0x73, 0x9F, 0x5D, 0x19, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x72, 0x39, 0x25, 0x67, 0x26, 0x6D, 0x71, 0x36, 0x77, 0x3C, 0x20, 0x62, 0x23, 0x68, 0x74, 0xC3, 0x82, 0xC9, 0x15, 0x57, 0x16, 0x5D, 0x81 }; static struct mpeg3_playkey mpeg3_pkey1a1 = {0x36b, {0x51,0x67,0x67,0xc5,0xe0}}; static struct mpeg3_playkey mpeg3_pkey2a1 = {0x762, {0x2c,0xb2,0xc1,0x09,0xee}}; static struct mpeg3_playkey mpeg3_pkey1b1 = {0x36b, {0x90,0xc1,0xd7,0x84,0x48}}; static struct mpeg3_playkey mpeg3_pkey1a2 = {0x2f3, {0x51,0x67,0x67,0xc5,0xe0}}; static struct mpeg3_playkey mpeg3_pkey2a2 = {0x730, {0x2c,0xb2,0xc1,0x09,0xee}}; static struct mpeg3_playkey mpeg3_pkey1b2 = {0x2f3, {0x90,0xc1,0xd7,0x84,0x48}}; static struct mpeg3_playkey mpeg3_pkey1a3 = {0x235, {0x51,0x67,0x67,0xc5,0xe0}}; static struct mpeg3_playkey mpeg3_pkey1b3 = {0x235, {0x90,0xc1,0xd7,0x84,0x48}}; static struct mpeg3_playkey mpeg3_pkey3a1 = {0x249, {0xb7,0x3f,0xd4,0xaa,0x14}}; /* DVD specific ? */ static struct mpeg3_playkey mpeg3_pkey4a1 = {0x028, {0x53,0xd4,0xf7,0xd9,0x8f}}; /* DVD specific ? */ static struct mpeg3_playkey *mpeg3_playkeys[] = { &mpeg3_pkey1a1, &mpeg3_pkey2a1, &mpeg3_pkey1b1, &mpeg3_pkey1a2, &mpeg3_pkey2a2, &mpeg3_pkey1b2, &mpeg3_pkey1a3, &mpeg3_pkey1b3, &mpeg3_pkey3a1, &mpeg3_pkey4a1, NULL }; /* * * some tables used for descrambling sectors and/or decrypting title keys * */ static unsigned char csstab1[256]= { 0x33,0x73,0x3b,0x26,0x63,0x23,0x6b,0x76,0x3e,0x7e,0x36,0x2b,0x6e,0x2e,0x66,0x7b, 0xd3,0x93,0xdb,0x06,0x43,0x03,0x4b,0x96,0xde,0x9e,0xd6,0x0b,0x4e,0x0e,0x46,0x9b, 0x57,0x17,0x5f,0x82,0xc7,0x87,0xcf,0x12,0x5a,0x1a,0x52,0x8f,0xca,0x8a,0xc2,0x1f, 0xd9,0x99,0xd1,0x00,0x49,0x09,0x41,0x90,0xd8,0x98,0xd0,0x01,0x48,0x08,0x40,0x91, 0x3d,0x7d,0x35,0x24,0x6d,0x2d,0x65,0x74,0x3c,0x7c,0x34,0x25,0x6c,0x2c,0x64,0x75, 0xdd,0x9d,0xd5,0x04,0x4d,0x0d,0x45,0x94,0xdc,0x9c,0xd4,0x05,0x4c,0x0c,0x44,0x95, 0x59,0x19,0x51,0x80,0xc9,0x89,0xc1,0x10,0x58,0x18,0x50,0x81,0xc8,0x88,0xc0,0x11, 0xd7,0x97,0xdf,0x02,0x47,0x07,0x4f,0x92,0xda,0x9a,0xd2,0x0f,0x4a,0x0a,0x42,0x9f, 0x53,0x13,0x5b,0x86,0xc3,0x83,0xcb,0x16,0x5e,0x1e,0x56,0x8b,0xce,0x8e,0xc6,0x1b, 0xb3,0xf3,0xbb,0xa6,0xe3,0xa3,0xeb,0xf6,0xbe,0xfe,0xb6,0xab,0xee,0xae,0xe6,0xfb, 0x37,0x77,0x3f,0x22,0x67,0x27,0x6f,0x72,0x3a,0x7a,0x32,0x2f,0x6a,0x2a,0x62,0x7f, 0xb9,0xf9,0xb1,0xa0,0xe9,0xa9,0xe1,0xf0,0xb8,0xf8,0xb0,0xa1,0xe8,0xa8,0xe0,0xf1, 0x5d,0x1d,0x55,0x84,0xcd,0x8d,0xc5,0x14,0x5c,0x1c,0x54,0x85,0xcc,0x8c,0xc4,0x15, 0xbd,0xfd,0xb5,0xa4,0xed,0xad,0xe5,0xf4,0xbc,0xfc,0xb4,0xa5,0xec,0xac,0xe4,0xf5, 0x39,0x79,0x31,0x20,0x69,0x29,0x61,0x70,0x38,0x78,0x30,0x21,0x68,0x28,0x60,0x71, 0xb7,0xf7,0xbf,0xa2,0xe7,0xa7,0xef,0xf2,0xba,0xfa,0xb2,0xaf,0xea,0xaa,0xe2,0xff }; static unsigned char lfsr1_bits0[256]= { 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x09,0x08,0x0b,0x0a,0x0d,0x0c,0x0f,0x0e, 0x12,0x13,0x10,0x11,0x16,0x17,0x14,0x15,0x1b,0x1a,0x19,0x18,0x1f,0x1e,0x1d,0x1c, 0x24,0x25,0x26,0x27,0x20,0x21,0x22,0x23,0x2d,0x2c,0x2f,0x2e,0x29,0x28,0x2b,0x2a, 0x36,0x37,0x34,0x35,0x32,0x33,0x30,0x31,0x3f,0x3e,0x3d,0x3c,0x3b,0x3a,0x39,0x38, 0x49,0x48,0x4b,0x4a,0x4d,0x4c,0x4f,0x4e,0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, 0x5b,0x5a,0x59,0x58,0x5f,0x5e,0x5d,0x5c,0x52,0x53,0x50,0x51,0x56,0x57,0x54,0x55, 0x6d,0x6c,0x6f,0x6e,0x69,0x68,0x6b,0x6a,0x64,0x65,0x66,0x67,0x60,0x61,0x62,0x63, 0x7f,0x7e,0x7d,0x7c,0x7b,0x7a,0x79,0x78,0x76,0x77,0x74,0x75,0x72,0x73,0x70,0x71, 0x92,0x93,0x90,0x91,0x96,0x97,0x94,0x95,0x9b,0x9a,0x99,0x98,0x9f,0x9e,0x9d,0x9c, 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x89,0x88,0x8b,0x8a,0x8d,0x8c,0x8f,0x8e, 0xb6,0xb7,0xb4,0xb5,0xb2,0xb3,0xb0,0xb1,0xbf,0xbe,0xbd,0xbc,0xbb,0xba,0xb9,0xb8, 0xa4,0xa5,0xa6,0xa7,0xa0,0xa1,0xa2,0xa3,0xad,0xac,0xaf,0xae,0xa9,0xa8,0xab,0xaa, 0xdb,0xda,0xd9,0xd8,0xdf,0xde,0xdd,0xdc,0xd2,0xd3,0xd0,0xd1,0xd6,0xd7,0xd4,0xd5, 0xc9,0xc8,0xcb,0xca,0xcd,0xcc,0xcf,0xce,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xff,0xfe,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf6,0xf7,0xf4,0xf5,0xf2,0xf3,0xf0,0xf1, 0xed,0xec,0xef,0xee,0xe9,0xe8,0xeb,0xea,0xe4,0xe5,0xe6,0xe7,0xe0,0xe1,0xe2,0xe3 }; static unsigned char lfsr1_bits1[512]= { 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff, 0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff,0x00,0x24,0x49,0x6d,0x92,0xb6,0xdb,0xff }; /* Reverse the order of the bits within a byte. */ static unsigned char bit_reverse[256]= { 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0, 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8, 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4, 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc, 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2, 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa, 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6, 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe, 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1, 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9, 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5, 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd, 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3, 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb, 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7, 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff }; /* ================================= Functions ====================================== */ /* * We use two LFSR's (seeded from some of the input data bytes) to * generate two streams of pseudo-random bits. These two bit streams * are then combined by simply adding with carry to generate a final * sequence of pseudo-random bits which is stored in the buffer that * 'output' points to the end of - len is the size of this buffer. * * The first LFSR is of degree 25, and has a polynomial of: * x^13 + x^5 + x^4 + x^1 + 1 * * The second LSFR is of degree 17, and has a (primitive) polynomial of: * x^15 + x^1 + 1 * * I don't know if these polynomials are primitive modulo 2, and thus * represent maximal-period LFSR's. * * * Note that we take the output of each LFSR from the new shifted in * bit, not the old shifted out bit. Thus for ease of use the LFSR's * are implemented in bit reversed order. * */ #define BIT0(x) ((x) & 1) #define BIT1(x) (((x) >> 1) & 1) static void generate_bits(unsigned char *output, int len, struct mpeg3_block const *s) { unsigned long lfsr0, lfsr1; unsigned char carry; /* In order to ensure that the LFSR works we need to ensure that the * initial values are non-zero. Thus when we initialise them from * the seed, we ensure that a bit is set. */ lfsr0 = (s->b[0] << 17) | (s->b[1] << 9) | ((s->b[2] & ~7) << 1) | 8 | (s->b[2] & 7); lfsr1 = (s->b[3] << 9) | 0x100 | s->b[4]; ++output; carry = 0; do{ int bit; unsigned char val; for (bit = 0, val = 0; bit < 8; ++bit) { unsigned char o_lfsr0, o_lfsr1; /* Actually only 1 bit each */ unsigned char combined; o_lfsr0 = ((lfsr0 >> 24) ^ (lfsr0 >> 21) ^ (lfsr0 >> 20) ^ (lfsr0 >> 12)) & 1; lfsr0 = (lfsr0 << 1) | o_lfsr0; o_lfsr1 = ((lfsr1 >> 16) ^ (lfsr1 >> 2)) & 1; lfsr1 = (lfsr1 << 1) | o_lfsr1; combined = !o_lfsr1 + carry + !o_lfsr0; carry = BIT1(combined); val |= BIT0(combined) << bit; } *--output = val; }while (--len > 0); } /* * This encryption engine implements one of 32 variations * one the same theme depending upon the choice in the * varient parameter (0 - 31). * * The algorithm itself manipulates a 40 bit input into * a 40 bit output. * The parameter 'input' is 80 bits. It consists of * the 40 bit input value that is to be encrypted followed * by a 40 bit seed value for the pseudo random number * generators. */ static void css_engine(int varient, unsigned char const *input, struct mpeg3_block *output) { unsigned char cse, term, index; struct mpeg3_block temp1; struct mpeg3_block temp2; unsigned char bits[30]; int i; /* Feed the secret into the input values such that * we alter the seed to the LFSR's used above, then * generate the bits to play with. */ for(i = 5; --i >= 0; ) temp1.b[i] = input[5 + i] ^ mpeg3css_secret[i] ^ mpeg3css_table2[i]; generate_bits(&bits[29], sizeof bits, &temp1); /* This term is used throughout the following to * select one of 32 different variations on the * algorithm. */ cse = mpeg3css_varients[varient] ^ mpeg3css_table2[varient]; /* Now the actual blocks doing the encryption. Each * of these works on 40 bits at a time and are quite * similar. */ for(i = 5, term = 0; --i >= 0; term = input[i]) { index = bits[25 + i] ^ input[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; temp1.b[i] = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; } temp1.b[4] ^= temp1.b[0]; for(i = 5, term = 0; --i >= 0; term = temp1.b[i]) { index = bits[20 + i] ^ temp1.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; temp2.b[i] = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; } temp2.b[4] ^= temp2.b[0]; for (i = 5, term = 0; --i >= 0; term = temp2.b[i]) { index = bits[15 + i] ^ temp2.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; index = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; temp1.b[i] = mpeg3css_table0[index] ^ mpeg3css_table2[index]; } temp1.b[4] ^= temp1.b[0]; for (i = 5, term = 0; --i >= 0; term = temp1.b[i]) { index = bits[10 + i] ^ temp1.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; index = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; temp2.b[i] = mpeg3css_table0[index] ^ mpeg3css_table2[index]; } temp2.b[4] ^= temp2.b[0]; for (i = 5, term = 0; --i >= 0; term = temp2.b[i]) { index = bits[5 + i] ^ temp2.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; temp1.b[i] = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; } temp1.b[4] ^= temp1.b[0]; for (i = 5, term = 0; --i >= 0; term = temp1.b[i]) { index = bits[i] ^ temp1.b[i]; index = mpeg3css_table1[index] ^ ~mpeg3css_table2[index] ^ cse; output->b[i] = mpeg3css_table2[index] ^ mpeg3css_table3[index] ^ term; } } static void crypt_key1(mpeg3_css_t *css, int varient, unsigned char const *challenge, struct mpeg3_block *key) { static unsigned char perm_challenge[] = {1, 3, 0, 7, 5, 2, 9, 6, 4, 8}; unsigned char scratch[10]; int i; for (i = 9; i >= 0; i--) scratch[i] = challenge[perm_challenge[i]]; css_engine(varient, scratch, key); } /* This shuffles the bits in varient to make perm_varient such that * 4 -> !3 * 3 -> 4 * varient bits: 2 -> 0 perm_varient bits * 1 -> 2 * 0 -> !1 */ static void crypt_key2(mpeg3_css_t *css, int varient, unsigned char const *challenge, struct mpeg3_block *key) { static unsigned char perm_challenge[] = {6, 1, 9, 3, 8, 5, 7, 4, 0, 2}; static unsigned char perm_varient[] = { 0x0a, 0x08, 0x0e, 0x0c, 0x0b, 0x09, 0x0f, 0x0d, 0x1a, 0x18, 0x1e, 0x1c, 0x1b, 0x19, 0x1f, 0x1d, 0x02, 0x00, 0x06, 0x04, 0x03, 0x01, 0x07, 0x05, 0x12, 0x10, 0x16, 0x14, 0x13, 0x11, 0x17, 0x15 }; unsigned char scratch[10]; int i; for(i = 9; i >= 0; i--) scratch[i] = css->challenge[perm_challenge[i]]; css_engine(perm_varient[varient], scratch, key); } /* This shuffles the bits in varient to make perm_varient such that * 4 -> 0 * 3 -> !1 * varient bits: 2 -> !4 perm_varient bits * 1 -> 2 * 0 -> 3 */ static void crypt_bus_key(mpeg3_css_t *css, int varient, unsigned char const *challenge, struct mpeg3_block *key) { static unsigned char perm_challenge[] = {4,0,3,5,7, 2,8,6,1,9}; static unsigned char perm_varient[] = { 0x12, 0x1a, 0x16, 0x1e, 0x02, 0x0a, 0x06, 0x0e, 0x10, 0x18, 0x14, 0x1c, 0x00, 0x08, 0x04, 0x0c, 0x13, 0x1b, 0x17, 0x1f, 0x03, 0x0b, 0x07, 0x0f, 0x11, 0x19, 0x15, 0x1d, 0x01, 0x09, 0x05, 0x0d}; unsigned char scratch[10]; int i; for(i = 9; i >= 0; i--) scratch[i] = css->challenge[perm_challenge[i]]; css_engine(perm_varient[varient], scratch, key); } static int get_asf(mpeg3_css_t *css) { dvd_authinfo ai; ai.type = DVD_LU_SEND_ASF; ai.lsasf.agid = 0; ai.lsasf.asf = 0; if(ioctl(css->fd, DVD_AUTH, &ai)) { /* Exit here for a hard drive or unencrypted CD-ROM. */ return 1; } return 0; } static int authenticate_drive(mpeg3_css_t *css, const unsigned char *key) { int i; for(i = 0; i < 5; i++) css->key1.b[i] = key[4 - i]; for(i = 0; i < 32; ++i) { crypt_key1(css, i, css->challenge, &(css->keycheck)); if(memcmp(css->keycheck.b, css->key1.b, 5) == 0) { css->varient = i; return 0; } } if (css->varient == -1) return 1; return 0; } /* Simulation of a non-CSS compliant host (i.e. the authentication fails, * but idea is here for a real CSS compliant authentication scheme). */ static int hostauth(mpeg3_css_t *css, dvd_authinfo *ai) { int i; switch(ai->type) { /* Host data receive (host changes state) */ case DVD_LU_SEND_AGID: ai->type = DVD_HOST_SEND_CHALLENGE; break; case DVD_LU_SEND_KEY1: /* printf("Key 1: %02x %02x %02x %02x %02x\n", */ /* ai->lsk.key[4], ai->lsk.key[3], ai->lsk.key[2], ai->lsk.key[1], ai->lsk.key[0]); */ if(authenticate_drive(css, ai->lsk.key)) { ai->type = DVD_AUTH_FAILURE; return 1; } ai->type = DVD_LU_SEND_CHALLENGE; break; case DVD_LU_SEND_CHALLENGE: for(i = 0; i < 10; i++) css->challenge[i] = ai->hsc.chal[9-i]; crypt_key2(css, css->varient, css->challenge, &(css->key2)); ai->type = DVD_HOST_SEND_KEY2; break; /* Host data send */ case DVD_HOST_SEND_CHALLENGE: for(i = 0; i < 10; i++) ai->hsc.chal[9 - i] = css->challenge[i]; /* Returning data, let LU change state */ break; case DVD_HOST_SEND_KEY2: for(i = 0; i < 5; i++) { ai->hsk.key[4 - i] = css->key2.b[i]; } /* printf("Key 2: %02x %02x %02x %02x %02x\n", */ /* ai->hsk.key[4], ai->hsk.key[3], ai->hsk.key[2], ai->hsk.key[1], ai->hsk.key[0]); */ /* Returning data, let LU change state */ break; default: fprintf(stderr, "Got invalid state %d\n", ai->type); return 1; } return 0; } static int get_title_key(mpeg3_css_t *css, int agid, int lba, unsigned char *key) { dvd_authinfo ai; int i; ai.type = DVD_LU_SEND_TITLE_KEY; ai.lstk.agid = agid; ai.lstk.lba = lba; if(ioctl(css->fd, DVD_AUTH, &ai)) { //perror("GetTitleKey"); return 1; } for (i = 0; i < 5; i++) { ai.lstk.title_key[i] ^= key[4 - (i % 5)]; } /* Save the title key */ for(i = 0; i < 5; i++) { css->title_key[i] = ai.lstk.title_key[i]; } return 0; } static int get_disk_key(mpeg3_css_t *css, int agid, unsigned char *key) { dvd_struct s; int index, i; s.type = DVD_STRUCT_DISCKEY; s.disckey.agid = agid; memset(s.disckey.value, 0, MPEG3_DVD_PACKET_SIZE); if(ioctl(css->fd, DVD_READ_STRUCT, &s) < 0) { /*perror("get_disk_key"); */ return 1; } for(index = 0; index < sizeof s.disckey.value; index ++) s.disckey.value[index] ^= key[4 - (index%5)]; /* Save disk key */ for(i = 0; i < MPEG3_DVD_PACKET_SIZE; i++) css->disk_key[i] = s.disckey.value[i]; return 0; } static int validate(mpeg3_css_t *css, int lba, int do_title) { dvd_authinfo ai; dvd_struct dvds; int result = 0; int i, rv, tries, agid; memset(&ai, 0, sizeof (ai)); memset(&dvds, 0, sizeof (dvds)); if(get_asf(css)) return 1; /* Init sequence, request AGID */ for(tries = 1, rv = -1; rv == -1 && tries < 4; tries++) { ai.type = DVD_LU_SEND_AGID; ai.lsa.agid = 0; rv = ioctl(css->fd, DVD_AUTH, &ai); if(rv == -1) { /* perror("validate: request AGID"); */ ai.type = DVD_INVALIDATE_AGID; ai.lsa.agid = 0; ioctl(css->fd, DVD_AUTH, &ai); } } if(tries >= 4) return 1; for(i = 0; i < 10; i++) css->challenge[i] = i; /* Send AGID to host */ if(hostauth(css, &ai)) return 1; /* Get challenge from host */ if(hostauth(css, &ai)) return 1; agid = ai.lsa.agid; /* Send challenge to LU */ if(ioctl(css->fd, DVD_AUTH, &ai) < 0) return 1; /* Get key1 from LU */ if(ioctl(css->fd, DVD_AUTH, &ai) < 0) return 1; /* Send key1 to host */ if(hostauth(css, &ai)) return 1; /* Get challenge from LU */ if(ioctl(css->fd, DVD_AUTH, &ai) < 0) return 1; /* Send challenge to host */ if(hostauth(css, &ai)) return 1; /* Get key2 from host */ if(hostauth(css, &ai)) return 1; /* Send key2 to LU */ if(ioctl(css->fd, DVD_AUTH, &ai) < 0) { perror("validate: Send key2 to LU"); return 1; } if(ai.type == DVD_AUTH_FAILURE) { fprintf(stderr, "validate: authorization failed\n"); return 1; } memcpy(css->challenge, css->key1.b, 5); memcpy(css->challenge + 5, css->key2.b, 5); crypt_bus_key(css, css->varient, css->challenge, &(css->keycheck)); get_asf(css); if(do_title) return get_title_key(css, agid, lba, css->keycheck.b); else return get_disk_key(css, agid, css->keycheck.b); return 0; } static int validate_path(mpeg3_css_t *css, int do_title) { int result = 0; int lba = 0, file_fd; if(do_title) { if((file_fd = open(css->path, O_RDONLY)) == -1) { perror("validate_path: open"); return 1; } if(ioctl(file_fd, FIBMAP, &lba) != 0) { perror("validate_path: FIBMAP"); close(file_fd); return 1; } close(file_fd); } result = mpeg3io_device(css->path, css->device_path); //printf("validate_path 1 %d\n", result); if(!result) result = (css->fd = open(css->device_path, O_RDONLY | O_NONBLOCK)) < 0; //printf("validate_path 2 %d\n", result); if(!result) result = validate(css, lba, do_title); //printf("validate_path 3 %d\n", result); /* Definitely encrypted if we got here. */ if(!result) css->encrypted = 1; close(css->fd); return result; } /* * * this function is only used internally when decrypting title key * */ static void title_key(unsigned char *key, unsigned char *im, unsigned char invert) { unsigned int lfsr1_lo, lfsr1_hi, lfsr0, combined; unsigned char o_lfsr0, o_lfsr1; unsigned char k[5]; int i; lfsr1_lo = im[0] | 0x100; lfsr1_hi = im[1]; lfsr0 = ((im[4] << 17) | (im[3] << 9) | (im[2] << 1)) + 8 - (im[2]&7); lfsr0 = (bit_reverse[lfsr0 & 0xff] << 24) | (bit_reverse[(lfsr0 >> 8) & 0xff] << 16) | (bit_reverse[(lfsr0 >> 16) & 0xff] << 8) | bit_reverse[(lfsr0 >> 24) & 0xff]; combined = 0; for (i = 0; i < 5; ++i) { o_lfsr1 = lfsr1_bits0[lfsr1_hi] ^ lfsr1_bits1[lfsr1_lo]; lfsr1_hi = lfsr1_lo>>1; lfsr1_lo = ((lfsr1_lo&1)<<8) ^ o_lfsr1; o_lfsr1 = bit_reverse[o_lfsr1]; /*o_lfsr0 = (lfsr0>>7)^(lfsr0>>10)^(lfsr0>>11)^(lfsr0>>19);*/ o_lfsr0 = (((((((lfsr0>>8)^lfsr0)>>1)^lfsr0)>>3)^lfsr0)>>7); lfsr0 = (lfsr0>>8)|(o_lfsr0<<24); combined += (o_lfsr0 ^ invert) + o_lfsr1; k[i] = combined & 0xff; combined >>= 8; } key[4] = k[4] ^ csstab1[key[4]] ^ key[3]; key[3] = k[3] ^ csstab1[key[3]] ^ key[2]; key[2] = k[2] ^ csstab1[key[2]] ^ key[1]; key[1] = k[1] ^ csstab1[key[1]] ^ key[0]; key[0] = k[0] ^ csstab1[key[0]] ^ key[4]; key[4] = k[4] ^ csstab1[key[4]] ^ key[3]; key[3] = k[3] ^ csstab1[key[3]] ^ key[2]; key[2] = k[2] ^ csstab1[key[2]] ^ key[1]; key[1] = k[1] ^ csstab1[key[1]] ^ key[0]; key[0] = k[0] ^ csstab1[key[0]]; } /* * * this function decrypts a title key with the specified disk key * * tkey: the unobfuscated title key (XORed with BusKey) * dkey: the unobfuscated disk key (XORed with BusKey) * 2048 bytes in length (though only 5 bytes are needed, see below) * * use the result returned in tkey with css_descramble * */ static int decrypt_title_key(mpeg3_css_t *css, unsigned char *dkey, unsigned char *tkey) { unsigned char test[5], pretkey[5]; int i = 0; for(i = 0; mpeg3_playkeys[i]; i++) { memcpy(pretkey, dkey + mpeg3_playkeys[i]->offset, 5); title_key(pretkey, mpeg3_playkeys[i]->key, 0); memcpy(test, dkey, 5); title_key(test, pretkey, 0); if(memcmp(test, pretkey, 5) == 0) break; } if(!mpeg3_playkeys[i]) { fprintf(stderr, "mpeg3_decrypttitlekey: Shit - Need key %d\n", i + 1); return 1; } title_key(css->title_key, pretkey, 0xff); return 0; } /* * * The descrambling core * * sec: encrypted sector (2048 bytes) * key: decrypted title key obtained from css_decrypttitlekey * */ #define SALTED(i) (key[i] ^ sec[0x54 - offset + (i)]) static void descramble(unsigned char *sec, unsigned char *key, int offset) { unsigned int lfsr1_lo, lfsr1_hi, lfsr0, combined; unsigned char o_lfsr0, o_lfsr1; unsigned char *end = sec + 0x800 - offset; if(offset > 0x54) fprintf(stderr, "mpeg3css.c: descramble: offset > 0x54 offset=%x\n", offset); lfsr1_lo = SALTED(0) | 0x100; lfsr1_hi = SALTED(1); lfsr0 = ((SALTED(4) << 17) | (SALTED(3) << 9) | (SALTED(2) << 1)) + 8 - (SALTED(2) & 7); lfsr0 = (bit_reverse[lfsr0 & 0xff] << 24) | (bit_reverse[(lfsr0 >> 8) & 0xff] << 16) | (bit_reverse[(lfsr0 >> 16) & 0xff] << 8) | bit_reverse[(lfsr0 >> 24) & 0xff]; sec += 0x80 - offset; combined = 0; while(sec != end) { o_lfsr1 = lfsr1_bits0[lfsr1_hi] ^ lfsr1_bits1[lfsr1_lo]; lfsr1_hi = lfsr1_lo >> 1; lfsr1_lo = ((lfsr1_lo&1) << 8) ^ o_lfsr1; o_lfsr1 = bit_reverse[o_lfsr1]; /*o_lfsr0 = (lfsr0 >> 7) ^ (lfsr0 >> 10) ^ (lfsr0 >> 11) ^ (lfsr0 >> 19);*/ o_lfsr0 = (((((((lfsr0 >> 8) ^ lfsr0) >> 1) ^ lfsr0) >> 3) ^ lfsr0) >> 7); lfsr0 = (lfsr0 >> 8) | (o_lfsr0 << 24); combined += o_lfsr0 + (unsigned char)~o_lfsr1; *sec = csstab1[*sec] ^ (combined & 0xff); sec++; combined >>= 8; } //printf("descramble\n"); } /* =============================== Entry Points ================================= */ mpeg3_css_t* mpeg3_new_css() { mpeg3_css_t *css = calloc(1, sizeof(mpeg3_css_t)); css->varient = -1; return css; } int mpeg3_delete_css(mpeg3_css_t *css) { free(css); return 0; } int mpeg3_get_keys(mpeg3_css_t *css, char *path) { int result = 0; strcpy(css->path, path); /* Get disk key */ result = validate_path(css, 0); /* Get title key */ if(!result) result = validate_path(css, 1); /* Descramble the title key */ if(!result) result = decrypt_title_key(css, css->disk_key, css->title_key); return css->encrypted ? result : 0; } /* sector is the full 2048 byte sector */ int mpeg3_decrypt_packet(mpeg3_css_t *css, unsigned char *sector, int offset) { //printf("mpeg3_decrypt_packet %d\n", css->encrypted); if(!css->encrypted) return 0; /* Not encrypted */ descramble(sector, css->title_key, offset); return 0; } #else // HAVE_CSS #include "mpeg3css_fake.c" #endif libmpeg3-1.5.4/mpeg3css_fake.c0000644000175000017500000000055007742725645016337 0ustar enderender00000000000000/* Stubs for deCSS which can't be distributed in source form */ #include "mpeg3css.h" #include "mpeg3private.h" mpeg3_css_t* mpeg3_new_css() { return 0; } int mpeg3_delete_css(mpeg3_css_t *css) { return 0; } int mpeg3_get_keys(mpeg3_css_t *css, char *path) { return 1; } int mpeg3_decrypt_packet(mpeg3_css_t *css, unsigned char *sector) { return 1; } libmpeg3-1.5.4/mpeg3css.h0000644000175000017500000000011407742725645015352 0ustar enderender00000000000000#ifndef MPEG3CSS_H #define MPEG3CSS_H #include "mpeg3private.inc" #endif libmpeg3-1.5.4/mpeg3demux.c0000644000175000017500000013667510012061157015674 0ustar enderender00000000000000#include "libmpeg3.h" #include "mpeg3io.h" #include "mpeg3protos.h" #include "workarounds.h" #include #include #include #include #define ABS(x) ((x) >= 0 ? (x) : -(x)) /* Don't advance pointer */ static inline unsigned char packet_next_char(mpeg3_demuxer_t *demuxer) { //printf(__FUNCTION__ " called\n"); return demuxer->raw_data[demuxer->raw_offset]; } /* Advance pointer */ static unsigned char packet_read_char(mpeg3_demuxer_t *demuxer) { unsigned char result = demuxer->raw_data[demuxer->raw_offset++]; //printf(__FUNCTION__ " called\n"); return result; } static inline unsigned int packet_read_int16(mpeg3_demuxer_t *demuxer) { unsigned int a, b, result; //printf(__FUNCTION__ " called\n"); a = demuxer->raw_data[demuxer->raw_offset++]; b = demuxer->raw_data[demuxer->raw_offset++]; result = (a << 8) | b; return result; } static inline unsigned int packet_next_int24(mpeg3_demuxer_t *demuxer) { unsigned int a, b, c, result; //printf(__FUNCTION__ " called\n"); a = demuxer->raw_data[demuxer->raw_offset]; b = demuxer->raw_data[demuxer->raw_offset + 1]; c = demuxer->raw_data[demuxer->raw_offset + 2]; result = (a << 16) | (b << 8) | c; return result; } static inline unsigned int packet_read_int24(mpeg3_demuxer_t *demuxer) { unsigned int a, b, c, result; //printf(__FUNCTION__ " called\n"); a = demuxer->raw_data[demuxer->raw_offset++]; b = demuxer->raw_data[demuxer->raw_offset++]; c = demuxer->raw_data[demuxer->raw_offset++]; result = (a << 16) | (b << 8) | c; return result; } static inline unsigned int packet_read_int32(mpeg3_demuxer_t *demuxer) { unsigned int a, b, c, d, result; //printf(__FUNCTION__ " called\n"); a = demuxer->raw_data[demuxer->raw_offset++]; b = demuxer->raw_data[demuxer->raw_offset++]; c = demuxer->raw_data[demuxer->raw_offset++]; d = demuxer->raw_data[demuxer->raw_offset++]; result = (a << 24) | (b << 16) | (c << 8) | d; return result; } static inline unsigned int packet_skip(mpeg3_demuxer_t *demuxer, long length) { //printf(__FUNCTION__ " called\n"); demuxer->raw_offset += length; return 0; } static int get_adaptation_field(mpeg3_demuxer_t *demuxer) { long length; int pcr_flag; demuxer->adaptation_fields++; /* get adaptation field length */ length = packet_read_char(demuxer); if(length > 0) { /* get first byte */ pcr_flag = (packet_read_char(demuxer) >> 4) & 1; if(pcr_flag) { unsigned long clk_ref_base = packet_read_int32(demuxer); unsigned int clk_ref_ext = packet_read_int16(demuxer); if (clk_ref_base > 0x7fffffff) { /* correct for invalid numbers */ clk_ref_base = 0; /* ie. longer than 32 bits when multiplied by 2 */ clk_ref_ext = 0; /* multiplied by 2 corresponds to shift left 1 (<<=1) */ } else { clk_ref_base <<= 1; /* Create space for bit */ clk_ref_base |= (clk_ref_ext >> 15); /* Take bit */ clk_ref_ext &= 0x01ff; /* Only lower 9 bits */ } demuxer->time = ((double)clk_ref_base + clk_ref_ext / 300) / 90000; if(length) packet_skip(demuxer, length - 7); } else packet_skip(demuxer, length - 1); } return 0; } static int get_program_association_table(mpeg3_demuxer_t *demuxer) { demuxer->program_association_tables++; demuxer->table_id = packet_read_char(demuxer); demuxer->section_length = packet_read_int16(demuxer) & 0xfff; demuxer->transport_stream_id = packet_read_int16(demuxer); packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset); return 0; } static int get_data_buffer(mpeg3_demuxer_t *demuxer) { while(demuxer->raw_offset < demuxer->raw_size && demuxer->data_size < MPEG3_RAW_SIZE) { demuxer->data_buffer[demuxer->data_size++] = demuxer->raw_data[demuxer->raw_offset++]; } return 0; } static int get_pes_packet_header(mpeg3_demuxer_t *demuxer, unsigned long *pts, unsigned long *dts) { unsigned int pes_header_bytes = 0; unsigned int pts_dts_flags; int pes_header_data_length; /* drop first 8 bits */ packet_read_char(demuxer); pts_dts_flags = (packet_read_char(demuxer) >> 6) & 0x3; pes_header_data_length = packet_read_char(demuxer); /* Get Presentation Time stamps and Decoding Time Stamps */ if(pts_dts_flags == 2) { *pts = (packet_read_char(demuxer) >> 1) & 7; /* Only low 4 bits (7==1111) */ *pts <<= 15; *pts |= (packet_read_int16(demuxer) >> 1); *pts <<= 15; *pts |= (packet_read_int16(demuxer) >> 1); pes_header_bytes += 5; } else if(pts_dts_flags == 3) { *pts = (packet_read_char(demuxer) >> 1) & 7; /* Only low 4 bits (7==1111) */ *pts <<= 15; *pts |= (packet_read_int16(demuxer) >> 1); *pts <<= 15; *pts |= (packet_read_int16(demuxer) >> 1); *dts = (packet_read_char(demuxer) >> 1) & 7; /* Only low 4 bits (7==1111) */ *dts <<= 15; *dts |= (packet_read_int16(demuxer) >> 1); *dts <<= 15; *dts |= (packet_read_int16(demuxer) >> 1); pes_header_bytes += 10; } demuxer->time = (double)*pts / 90000; //printf("get_pes_packet_header %f\n", demuxer->time); /* extract other stuff here! */ packet_skip(demuxer, pes_header_data_length - pes_header_bytes); return 0; } static int get_unknown_data(mpeg3_demuxer_t *demuxer) { packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset); return 0; } // Combine the pid and the stream id into one unit #define CUSTOM_ID(pid, stream_id) (((pid << 8) | stream_id) & 0xffff) static int get_pes_packet_data(mpeg3_demuxer_t *demuxer, unsigned int stream_id) { unsigned long pts = 0, dts = 0; get_pes_packet_header(demuxer, &pts, &dts); //printf("get_pes_packet_data %x\n", CUSTOM_ID(demuxer->pid, stream_id)); if(stream_id == 0xbd) { // Don't know if the next byte is the true stream id like in program stream stream_id = 0x0; if(demuxer->read_all) demuxer->astream_table[CUSTOM_ID(demuxer->pid, stream_id)] = AUDIO_AC3; if(demuxer->astream == -1) demuxer->astream = CUSTOM_ID(demuxer->pid, stream_id); if(CUSTOM_ID(demuxer->pid, stream_id) == demuxer->astream && demuxer->do_audio) { demuxer->pes_audio_time = (double)pts / 90000; demuxer->audio_pid = demuxer->pid; return get_data_buffer(demuxer); } } else if((stream_id >> 4) == 12 || (stream_id >> 4) == 13) { /* Just pick the first available stream if no ID is set */ if(demuxer->read_all) demuxer->astream_table[CUSTOM_ID(demuxer->pid, stream_id)] = AUDIO_MPEG; if(demuxer->astream == -1) demuxer->astream = CUSTOM_ID(demuxer->pid, stream_id); if(CUSTOM_ID(demuxer->pid, stream_id) == demuxer->astream && demuxer->do_audio) { demuxer->pes_audio_time = (double)pts / 90000; demuxer->audio_pid = demuxer->pid; return get_data_buffer(demuxer); } } else if((stream_id >> 4) == 14) { //printf("get_pes_packet_data video %x\n", stream_id); /* Just pick the first available stream if no ID is set */ if(demuxer->read_all) demuxer->vstream_table[CUSTOM_ID(demuxer->pid, stream_id)] = 1; else if(demuxer->vstream == -1) demuxer->vstream = (CUSTOM_ID(demuxer->pid, stream_id)); //printf("get_pes_packet_data %x %d\n", stream_id, demuxer->payload_unit_start_indicator); if(CUSTOM_ID(demuxer->pid, stream_id) == demuxer->vstream && demuxer->do_video) { demuxer->pes_video_time = (double)pts / 90000; demuxer->video_pid = demuxer->pid; /* * printf("get_pes_packet_data video %04x %llx\n", * stream_id, * mpeg3io_tell(demuxer->titles[demuxer->current_title]->fs)); * int i; * for(i = demuxer->raw_offset; i < demuxer->raw_size; i++) * printf("%02x ", demuxer->raw_data[i], stdout); * printf("\n"); */ return get_data_buffer(demuxer); } } else { return get_unknown_data(demuxer); } packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset); return 0; } static int get_pes_packet(mpeg3_demuxer_t *demuxer) { unsigned int stream_id; demuxer->pes_packets++; /* Skip startcode */ packet_read_int24(demuxer); stream_id = packet_read_char(demuxer); /* Skip pes packet length */ packet_read_int16(demuxer); if(stream_id != MPEG3_PRIVATE_STREAM_2 && stream_id != MPEG3_PADDING_STREAM) { return get_pes_packet_data(demuxer, stream_id); } else if(stream_id == MPEG3_PRIVATE_STREAM_2) { /* Dump private data! */ fprintf(stderr, "stream_id == MPEG3_PRIVATE_STREAM_2\n"); packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset); return 0; } else if(stream_id == MPEG3_PADDING_STREAM) { packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset); return 0; } else { fprintf(stderr, "unknown stream_id in pes packet"); return 1; } return 0; } static int get_payload(mpeg3_demuxer_t *demuxer) { //printf("get_payload 1 %x %d\n", demuxer->pid, demuxer->payload_unit_start_indicator); if(demuxer->payload_unit_start_indicator) { if(demuxer->pid==0) get_program_association_table(demuxer); else if(packet_next_int24(demuxer) == MPEG3_PACKET_START_CODE_PREFIX) get_pes_packet(demuxer); else packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset); } else { //printf("get_payload 2\n"); if(demuxer->pid == demuxer->audio_pid && demuxer->do_audio) { get_data_buffer(demuxer); } else if(demuxer->pid == demuxer->video_pid && demuxer->do_video) { get_data_buffer(demuxer); } else packet_skip(demuxer, demuxer->raw_size - demuxer->raw_offset); } return 0; } /* Read a transport packet */ static int read_transport(mpeg3_demuxer_t *demuxer) { mpeg3_t *file = (mpeg3_t*)demuxer->file; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; int result = 0; unsigned int bits; int table_entry; /* Packet size is known for transport streams */ demuxer->raw_size = file->packet_size; demuxer->raw_offset = 0; if(result) { perror("read_transport"); return 1; } //printf("read transport 1 %llx %llx\n", title->fs->current_byte, title->fs->total_bytes); // Search for Sync byte */ do { bits = mpeg3io_read_char(title->fs); }while(!mpeg3io_eof(title->fs) && !result && bits != MPEG3_SYNC_BYTE); /* Hit EOF */ if(mpeg3io_eof(title->fs) || result) return 1; /* * printf("read transport 2 bits=%x tell=%llx packet_size=%x\n", * bits, * mpeg3io_tell(title->fs), * file->packet_size); */ if(bits == MPEG3_SYNC_BYTE && !result) { demuxer->raw_data[0] = MPEG3_SYNC_BYTE; result = mpeg3io_read_data(demuxer->raw_data + 1, file->packet_size - 1, title->fs); } else { demuxer->absolute_byte = mpeg3io_tell(title->fs) + title->start_byte; return 1; } packet_read_char(demuxer); bits = packet_read_int24(demuxer) & 0x00ffffff; //printf("read transport 3 tell=%x bits=%x\n", mpeg3io_tell(title->fs), bits); demuxer->transport_error_indicator = (bits >> 23) & 0x1; demuxer->payload_unit_start_indicator = (bits >> 22) & 0x1; demuxer->pid = (bits >> 8) & 0x00001fff; demuxer->transport_scrambling_control = (bits >> 6) & 0x3; demuxer->adaptation_field_control = (bits >> 4) & 0x3; demuxer->continuity_counter = bits & 0xf; //printf("read_transport 1 %llx %08x %d\n", mpeg3io_tell(title->fs), bits, demuxer->payload_unit_start_indicator); //printf("read_transport 4 %x\n", demuxer->pid); if(demuxer->transport_error_indicator) { fprintf(stderr, "demuxer->transport_error_indicator\n"); demuxer->absolute_byte = mpeg3io_tell(title->fs) + title->start_byte; return 1; } //printf("read_transport 5 %x\n", demuxer->pid); if (demuxer->pid == 0x1fff) { demuxer->is_padding = 1; /* padding; just go to next */ } else { demuxer->is_padding = 0; } //printf("read_transport 6 %x\n", demuxer->pid); /* Get pid from table */ for(table_entry = 0, result = 0; table_entry < demuxer->total_pids; table_entry++) { if(demuxer->pid == demuxer->pid_table[table_entry]) { result = 1; break; } } //printf("read_transport 7 %x\n", demuxer->pid); /* Not in pid table */ if(!result) { demuxer->pid_table[table_entry] = demuxer->pid; demuxer->continuity_counters[table_entry] = demuxer->continuity_counter; /* init */ demuxer->total_pids++; } result = 0; /* Abort if padding. Should abort after demuxer->pid == 0x1fff for speed. */ if(demuxer->is_padding) { demuxer->absolute_byte = mpeg3io_tell(title->fs) + title->start_byte; return 0; } #if 0 /* Check counters */ if(demuxer->pid != MPEG3_PROGRAM_ASSOCIATION_TABLE && demuxer->pid != MPEG3_CONDITIONAL_ACCESS_TABLE && (demuxer->adaptation_field_control == 1 || demuxer->adaptation_field_control == 3)) { if(demuxer->continuity_counters[table_entry] != demuxer->continuity_counter) { // fprintf(stderr, "demuxer->continuity_counters[table_entry] != demuxer->continuity_counter\n"); /* Reset it */ demuxer->continuity_counters[table_entry] = demuxer->continuity_counter; } if(++(demuxer->continuity_counters[table_entry]) > 15) demuxer->continuity_counters[table_entry] = 0; } #endif if(demuxer->adaptation_field_control == 2 || demuxer->adaptation_field_control == 3) result = get_adaptation_field(demuxer); // Need to enter in astream and vstream table: // PID ored with stream_id if(demuxer->adaptation_field_control == 1 || demuxer->adaptation_field_control == 3) result = get_payload(demuxer); demuxer->absolute_byte = mpeg3io_tell(title->fs) + title->start_byte; return result; } static int get_system_header(mpeg3_demuxer_t *demuxer) { mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; int length = mpeg3io_read_int16(title->fs); mpeg3io_seek_relative(title->fs, length); return 0; } static unsigned long get_timestamp(mpeg3_demuxer_t *demuxer) { unsigned long timestamp; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; /* Only low 4 bits (7==1111) */ timestamp = (mpeg3io_read_char(title->fs) >> 1) & 7; timestamp <<= 15; timestamp |= (mpeg3io_read_int16(title->fs) >> 1); timestamp <<= 15; timestamp |= (mpeg3io_read_int16(title->fs) >> 1); return timestamp; } static int get_pack_header(mpeg3_demuxer_t *demuxer) { unsigned long i, j; unsigned long clock_ref, clock_ref_ext; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; /* Get the time code */ if((mpeg3io_next_char(title->fs) >> 4) == 2) { /* MPEG-1 */ demuxer->time = (double)get_timestamp(demuxer) / 90000; /* Skip 3 bytes */ mpeg3io_read_int24(title->fs); } else if(mpeg3io_next_char(title->fs) & 0x40) { i = mpeg3io_read_int32(title->fs); j = mpeg3io_read_int16(title->fs); if(i & 0x40000000 || (i >> 28) == 2) { clock_ref = ((i & 0x38000000) << 3); clock_ref |= ((i & 0x03fff800) << 4); clock_ref |= ((i & 0x000003ff) << 5); clock_ref |= ((j & 0xf800) >> 11); clock_ref_ext = (j >> 1) & 0x1ff; demuxer->time = (double)(clock_ref + clock_ref_ext / 300) / 90000; /* Skip 3 bytes */ mpeg3io_read_int24(title->fs); i = mpeg3io_read_char(title->fs) & 0x7; /* stuffing */ mpeg3io_seek_relative(title->fs, i); } } else { mpeg3io_seek_relative(title->fs, 2); } return 0; } /* Program packet reading core */ static int get_ps_pes_packet(mpeg3_demuxer_t *demuxer, unsigned int header) { unsigned long pts = 0, dts = 0; int stream_id; int pes_packet_length; int64_t pes_packet_start; long decryption_offset; int i; mpeg3_t *file = demuxer->file; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; int scrambling = 0; int data_start = demuxer->data_size; /* Format if audio */ int do_pcm = 0; stream_id = header & 0xff; pes_packet_length = mpeg3io_read_int16(title->fs); pes_packet_start = mpeg3io_tell(title->fs); /* * printf(__FUNCTION__ " pes_packet_start=%llx pes_packet_length=%x data_size=%x\n", * pes_packet_start, * pes_packet_length, * demuxer->data_size); */ if(stream_id != MPEG3_PRIVATE_STREAM_2 && stream_id != MPEG3_PADDING_STREAM) { if((mpeg3io_next_char(title->fs) >> 6) == 0x02) { /* Get MPEG-2 packet */ int pes_header_bytes = 0; int pts_dts_flags; int pes_header_data_length; demuxer->last_packet_decryption = mpeg3io_tell(title->fs); scrambling = mpeg3io_read_char(title->fs) & 0x30; //scrambling = 1; /* Reset scrambling bit for the mpeg3cat utility */ // if(scrambling) demuxer->raw_data[demuxer->raw_offset - 1] &= 0xcf; // Force packet length if scrambling if(scrambling) pes_packet_length = 0x800 - pes_packet_start + demuxer->last_packet_start; pts_dts_flags = (mpeg3io_read_char(title->fs) >> 6) & 0x3; pes_header_data_length = mpeg3io_read_char(title->fs); /* Get Presentation and Decoding Time Stamps */ if(pts_dts_flags == 2) { pts = (mpeg3io_read_char(title->fs) >> 1) & 7; /* Only low 4 bits (7==1111) */ pts <<= 15; pts |= (mpeg3io_read_int16(title->fs) >> 1); pts <<= 15; pts |= (mpeg3io_read_int16(title->fs) >> 1); pes_header_bytes += 5; } else if(pts_dts_flags == 3) { pts = (mpeg3io_read_char(title->fs) >> 1) & 7; /* Only low 4 bits (7==1111) */ pts <<= 15; pts |= (mpeg3io_read_int16(title->fs) >> 1); pts <<= 15; pts |= (mpeg3io_read_int16(title->fs) >> 1); dts = (mpeg3io_read_char(title->fs) >> 1) & 7; /* Only low 4 bits (7==1111) */ dts <<= 15; dts |= (mpeg3io_read_int16(title->fs) >> 1); dts <<= 15; dts |= (mpeg3io_read_int16(title->fs) >> 1); pes_header_bytes += 10; } //printf("get_ps_pes_packet do_audio=%d do_video=%d pts=%x dts=%x\n", // demuxer->do_audio, demuxer->do_video, pts, dts); /* Skip unknown */ mpeg3io_seek_relative(title->fs, pes_header_data_length - pes_header_bytes); } else { int pts_dts_flags; /* Get MPEG-1 packet */ while(mpeg3io_next_char(title->fs) == 0xff) { mpeg3io_read_char(title->fs); } /* Skip STD buffer scale */ if((mpeg3io_next_char(title->fs) & 0x40) == 0x40) { mpeg3io_seek_relative(title->fs, 2); } /* Decide which timestamps are available */ pts_dts_flags = mpeg3io_next_char(title->fs); if(pts_dts_flags >= 0x30) { /* Get the presentation and decoding time stamp */ pts = get_timestamp(demuxer); dts = get_timestamp(demuxer); } else if(pts_dts_flags >= 0x20) { /* Get just the presentation time stamp */ pts = get_timestamp(demuxer); } else if(pts_dts_flags == 0x0f) { /* End of timestamps */ mpeg3io_read_char(title->fs); } else { return 1; /* Error */ } } /* Now extract the payload. */ if((stream_id >> 4) == 0xc || (stream_id >> 4) == 0xd) { /* Audio data */ /* Take first stream ID if -1 */ pes_packet_length -= mpeg3io_tell(title->fs) - pes_packet_start; if(demuxer->read_all) demuxer->astream_table[stream_id & 0x0f] = AUDIO_MPEG; else if(demuxer->astream == -1) demuxer->astream = stream_id & 0x0f; if(pts > 0) demuxer->pes_audio_time = (double)pts / 60000; if((stream_id & 0x0f) == demuxer->astream && demuxer->do_audio) { decryption_offset = mpeg3io_tell(title->fs) - demuxer->last_packet_start; mpeg3io_read_data(demuxer->data_buffer + demuxer->data_size, pes_packet_length, title->fs); demuxer->data_size += pes_packet_length; } else { mpeg3io_seek_relative(title->fs, pes_packet_length); } } else if((stream_id >> 4) == 0xe) { /* Video data */ /* Take first stream ID if -1 */ pes_packet_length -= mpeg3io_tell(title->fs) - pes_packet_start; if(demuxer->read_all) demuxer->vstream_table[stream_id & 0x0f] = 1; else if(demuxer->vstream == -1) demuxer->vstream = stream_id & 0x0f; if(pts > 0) demuxer->pes_video_time = (double)pts / 60000; if((stream_id & 0x0f) == demuxer->vstream && demuxer->do_video) { //printf(__FUNCTION__ " stream_id=%x size=%x\n", stream_id, pes_packet_length); decryption_offset = mpeg3io_tell(title->fs) - demuxer->last_packet_start; mpeg3io_read_data(demuxer->data_buffer + demuxer->data_size, pes_packet_length, title->fs); demuxer->data_size += pes_packet_length; } else { mpeg3io_seek_relative(title->fs, pes_packet_length); } } else if((stream_id == 0xbd || stream_id == 0xbf) && mpeg3io_next_char(title->fs) != 0xff && ((mpeg3io_next_char(title->fs) & 0xf0) != 0x20)) { int format; /* DVD audio data */ /* Get the audio format */ if((mpeg3io_next_char(title->fs) & 0xf0) == 0xa0) format = AUDIO_PCM; else format = AUDIO_AC3; // Picks up bogus data if (& 0xf) or (& 0x7f) stream_id = mpeg3io_next_char(title->fs); if(pts > 0) demuxer->pes_audio_time = (double)pts / 60000; //printf("get_ps_pes_packet %x\n", stream_id); /* Take first stream ID if not building TOC. */ if(demuxer->read_all) demuxer->astream_table[stream_id] = format; else if(demuxer->astream == -1) demuxer->astream = stream_id; //printf("get_ps_pes_packet 5 %x\n", format); if(stream_id == demuxer->astream && demuxer->do_audio) { demuxer->aformat = format; mpeg3io_read_int32(title->fs); pes_packet_length -= mpeg3io_tell(title->fs) - pes_packet_start; decryption_offset = mpeg3io_tell(title->fs) - demuxer->last_packet_start; if(format == AUDIO_PCM) do_pcm = 1; //printf("get_ps_pes_packet 5 %x\n", decryption_offset); mpeg3io_read_data(demuxer->data_buffer + demuxer->data_size, pes_packet_length, title->fs); demuxer->data_size += pes_packet_length; } else { pes_packet_length -= mpeg3io_tell(title->fs) - pes_packet_start; mpeg3io_seek_relative(title->fs, pes_packet_length); } //printf("get_ps_pes_packet 6 %d\n", demuxer->astream_table[0x20]); } else if(stream_id == 0xbc || 1) { pes_packet_length -= mpeg3io_tell(title->fs) - pes_packet_start; mpeg3io_seek_relative(title->fs, pes_packet_length); } } else if(stream_id == MPEG3_PRIVATE_STREAM_2 || stream_id == MPEG3_PADDING_STREAM) { pes_packet_length -= mpeg3io_tell(title->fs) - pes_packet_start; mpeg3io_seek_relative(title->fs, pes_packet_length); //printf(__FUNCTION__ " 2 %llx\n", mpeg3io_tell(title->fs)); } // Advance 2048 bytes if scrambled. We might pick up a spurrius // packet start code in the scrambled data otherwise. if(scrambling && demuxer->last_packet_start + 0x800 > mpeg3io_tell(title->fs)) { mpeg3io_seek_relative(title->fs, demuxer->last_packet_start + 0x800 - mpeg3io_tell(title->fs)); } // Descramble if desired if(demuxer->data_size && scrambling) { //printf(__FUNCTION__ " data_size=%x decryption_offset=%x\n", demuxer->data_size, decryption_offset); if(mpeg3_decrypt_packet(title->fs->css, demuxer->data_buffer, decryption_offset)) { fprintf(stderr, "get_ps_pes_packet: Decryption not available\n"); return 1; } } /* Synthesize PCM header and delete MPEG header for PCM data */ /* Must be done after decryption */ if(do_pcm) { unsigned char code; int bits_code; int bits; int samplerate_code; int samplerate; unsigned char *output = demuxer->data_buffer + data_start; int j; /* Shift audio back */ code = output[1]; for(i = demuxer->data_size - 1, j = demuxer->data_size + PCM_HEADERSIZE - 3 - 1; i >= data_start; i--, j--) *(demuxer->data_buffer + j) = *(demuxer->data_buffer + i); demuxer->data_size += PCM_HEADERSIZE - 3; bits_code = (code >> 6) & 3; samplerate_code = (code & 0x10); output[0] = 0x7f; output[1] = 0x7f; output[2] = 0x80; output[3] = 0x7f; /* Samplerate */ switch(samplerate_code) { case 1: samplerate = 96000; break; default: samplerate = 48000; break; } *(int32_t*)(output + 4) = samplerate; /* Bits */ switch(bits_code) { case 0: bits = 16; break; case 1: bits = 20; break; case 2: bits = 24; break; default: bits = 16; break; } *(int32_t*)(output + 8) = bits; /* Channels */ *(int32_t*)(output + 12) = (code & 0x7) + 1; /* Framesize */ *(int32_t*)(output + 16) = pes_packet_length - 3 + PCM_HEADERSIZE; //printf(__FUNCTION__ " %02x%02x%02x %d\n", code1, code, code2, pes_packet_length - 3); } //printf(__FUNCTION__ " 3 %llx %x\n", mpeg3io_tell(title->fs), demuxer->data_size); //if(mpeg3io_tell(title->fs) - demuxer->last_packet_start != 0x800) //printf(__FUNCTION__ " packet size == %llx\n", mpeg3io_tell(title->fs) - demuxer->last_packet_start); //printf(__FUNCTION__ " pes_audio_time=%f pes_video_time=%f\n", demuxer->pes_audio_time, demuxer->pes_video_time); return 0; } int mpeg3demux_read_program(mpeg3_demuxer_t *demuxer) { int result = 0; int count = 0; mpeg3_t *file = demuxer->file; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; unsigned int header = 0; int pack_count = 0; demuxer->data_size = 0; //printf("mpeg3demux_read_program 1 %d %llx %llx\n", result, title->fs->current_byte, title->fs->total_bytes); if(mpeg3io_eof(title->fs)) return 1; //printf("mpeg3demux_read_program 2 %d %x %llx\n", result, title->fs->current_byte, title->fs->total_bytes); /* Search for next header */ /* Parse packet until the next packet start code */ while(!result && !mpeg3io_eof(title->fs)) { header = mpeg3io_read_int32(title->fs); if(header == MPEG3_PACK_START_CODE) { // Second start code in this call. Don't read it. if(pack_count) { mpeg3io_seek_relative(title->fs, -4); break; } demuxer->last_packet_start = mpeg3io_tell(title->fs) - 4; result = get_pack_header(demuxer); //printf("mpeg3demux_read_program MPEG3_PACK_START_CODE %d\n", result); pack_count++; } else if(header == MPEG3_SYSTEM_START_CODE && pack_count) { result = get_system_header(demuxer); //printf("mpeg3demux_read_program MPEG3_SYSTEM_START_CODE %d\n", result); } else if((header >> 8) == MPEG3_PACKET_START_CODE_PREFIX && pack_count) { result = get_ps_pes_packet(demuxer, header); //printf("mpeg3demux_read_program MPEG3_PACKET_START_CODE_PREFIX %d %08x\n", result, header); } else { // Try again. //printf(__FUNCTION__ " %llx %08x\n", mpeg3io_tell(title->fs), header); mpeg3io_seek_relative(title->fs, -3); } } //printf("mpeg3demux_read_program 3 %d %x %llx\n", result, title->fs->current_byte, title->fs->total_bytes); // Ignore errors in the parsing. Just quit if eof. result = 0; demuxer->last_packet_end = mpeg3io_tell(title->fs); /* * if(demuxer->last_packet_end - demuxer->last_packet_start != 0x800) * printf(__FUNCTION__ " packet_size=%llx data_size=%x pack_count=%d packet_start=%llx packet_end=%llx\n", * demuxer->last_packet_end - demuxer->last_packet_start, * demuxer->data_size, * pack_count, * demuxer->last_packet_start, * demuxer->last_packet_end); */ //printf("mpeg3demux_read_program 5 %d\n", result); //printf("read_program 3\n"); // if(!result) result = mpeg3io_eof(title->fs); demuxer->absolute_byte = mpeg3io_tell(title->fs) + title->start_byte; return result; } int mpeg3_advance_cell(mpeg3_demuxer_t *demuxer) { mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; mpeg3io_seek(title->fs, demuxer->absolute_byte - title->start_byte); //printf("mpeg3_advance_cell %llx %llx\n",demuxer->absolute_byte , title->start_byte); /* Don't do anything when constructing cell table */ if(!title->cell_table || !title->cell_table_size || demuxer->read_all) { return 0; } mpeg3demux_cell_t *cell = &title->cell_table[demuxer->title_cell]; //printf("mpeg3_advance_cell 1\n"); /* Don't do anything if we're in the cell and it's the right program */ if(demuxer->reverse) { /* * printf("mpeg3_advance_cell 1 %llx %llx %llx %llx %llx\n", * demuxer->absolute_byte, * cell->start_byte, * cell->end_byte, * title->start_byte, * title->end_byte);fflush(stdout); */ if(demuxer->absolute_byte > cell->start_byte + title->start_byte && demuxer->absolute_byte <= cell->end_byte + title->start_byte && cell->program == demuxer->current_program) { return 0; } } else { if(demuxer->absolute_byte >= cell->start_byte + title->start_byte && demuxer->absolute_byte < cell->end_byte + title->start_byte && cell->program == demuxer->current_program) return 0; } //printf("mpeg3_advance_cell 10\n"); int result = 0; int last_cell = demuxer->title_cell; int last_title = demuxer->current_title; int64_t last_byte = demuxer->absolute_byte; int got_it = 0; /* * printf("mpeg3_advance_cell 2 %llx %llx %llx %llx %llx\n", * demuxer->absolute_byte, * cell->start_byte + title->start_byte, * cell->end_byte + title->start_byte, * title->start_byte, * title->end_byte);fflush(stdout); */ /* Find first cell on or after current position */ if(demuxer->reverse) { for(demuxer->current_title = demuxer->total_titles - 1; demuxer->current_title >= 0; demuxer->current_title--) { title = demuxer->titles[demuxer->current_title]; if(title->start_byte < demuxer->absolute_byte) { for(demuxer->title_cell = title->cell_table_size - 1; demuxer->title_cell >= 0; demuxer->title_cell--) { cell = &title->cell_table[demuxer->title_cell]; if(cell->start_byte + title->start_byte < demuxer->absolute_byte && cell->program == demuxer->current_program) { got_it = 1; if(demuxer->absolute_byte > cell->end_byte + title->start_byte) demuxer->absolute_byte = cell->end_byte + title->start_byte; break; } } } if(got_it) break; } if(!got_it) { demuxer->current_title = 0; demuxer->title_cell = 0; result = 1; } //printf("mpeg3_advance_cell 10\n"); } else { //printf("mpeg3_advance_cell 20\n"); for(demuxer->current_title = 0; demuxer->current_title < demuxer->total_titles; demuxer->current_title++) { title = demuxer->titles[demuxer->current_title]; if(title->end_byte > demuxer->absolute_byte) { for(demuxer->title_cell = 0; demuxer->title_cell < title->cell_table_size; demuxer->title_cell++) { cell = &title->cell_table[demuxer->title_cell]; if(cell->end_byte + title->start_byte > demuxer->absolute_byte && cell->program == demuxer->current_program) { got_it = 1; if(demuxer->absolute_byte < cell->start_byte + title->start_byte) demuxer->absolute_byte = cell->start_byte + title->start_byte; break; } } } if(got_it) break; } if(!got_it) { demuxer->current_title = demuxer->total_titles - 1; title = demuxer->titles[demuxer->current_title]; demuxer->title_cell = title->cell_table_size - 1; result = 1; } //printf("mpeg3_advance_cell 30\n"); } /* * printf("mpeg3_advance_cell 40 %llx %llx %llx %llx %llx\n", * demuxer->absolute_byte, * cell->start_byte + title->start_byte, * cell->end_byte + title->start_byte, * title->start_byte, * title->end_byte);fflush(stdout); */ if(demuxer->current_title != last_title) { mpeg3demux_open_title(demuxer, demuxer->current_title); } title = demuxer->titles[demuxer->current_title]; if(demuxer->absolute_byte != title->start_byte + mpeg3io_tell(title->fs)) { mpeg3io_seek(title->fs, demuxer->absolute_byte - title->start_byte); } //printf("mpeg3_advance_cell 40\n", demuxer->absolute_byte); return result; } static int next_code(mpeg3_demuxer_t *demuxer, uint32_t code) { uint32_t result = 0; int error = 0; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; mpeg3_fs_t *fd = title->fs; while(result != code && !error) { title = demuxer->titles[demuxer->current_title]; result <<= 8; result |= (unsigned char)mpeg3io_read_char(title->fs); demuxer->absolute_byte++; error = mpeg3_advance_cell(demuxer); } return error; } /* Read packet in the forward direction */ int mpeg3_read_next_packet(mpeg3_demuxer_t *demuxer) { int result = 0; long current_position; mpeg3_t *file = demuxer->file; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; /* * printf("mpeg3_read_next_packet 1 %d %llx\n", result, demuxer->absolute_byte); * fflush(stdout); */ /* Reset output buffer */ demuxer->data_size = 0; demuxer->data_position = 0; /* Switch to forward direction. */ if(demuxer->reverse) { /* Don't reread anything if we're at the beginning of the file. */ if(demuxer->absolute_byte < 0) { demuxer->absolute_byte = 0; result = mpeg3_advance_cell(demuxer); /* First character was the -1 byte which brings us to 0 after this function. */ result = 1; } else /* Transport or elementary stream */ if(file->packet_size > 0) { demuxer->absolute_byte += file->packet_size; result = mpeg3_advance_cell(demuxer); } else { /* Packet just read */ if(!result) result = next_code(demuxer, MPEG3_PACK_START_CODE); /* Next packet */ if(!result) result = next_code(demuxer, MPEG3_PACK_START_CODE); } demuxer->reverse = 0; } //printf("mpeg3_read_next_packet 2 %llx\n", demuxer->absolute_byte); /* Read packets until the output buffer is full */ if(!result) { do { title = demuxer->titles[demuxer->current_title]; if(!result) { if(file->is_transport_stream) { result = read_transport(demuxer); if(!result) result = mpeg3_advance_cell(demuxer); } else if(file->is_program_stream) { result = mpeg3demux_read_program(demuxer); if(!result) result = mpeg3_advance_cell(demuxer); } else { /* Read elementary stream. */ result = mpeg3io_read_data(demuxer->data_buffer, file->packet_size, title->fs); if(!result) { demuxer->data_size = file->packet_size; demuxer->absolute_byte += file->packet_size; result = mpeg3_advance_cell(demuxer); } } } }while(!result && demuxer->data_size == 0 && (demuxer->do_audio || demuxer->do_video)); } //printf("mpeg3_read_next_packet 3\n"); /* * printf("mpeg3_read_next_packet 2 %d %llx\n", result, demuxer->absolute_byte); * fflush(stdout); */ return result; } static int prev_code(mpeg3_demuxer_t *demuxer, uint32_t code) { uint32_t result = 0; int error = 0; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; mpeg3_fs_t *fd = title->fs; while(result != code && demuxer->absolute_byte > 0 && !error) { result >>= 8; title = demuxer->titles[demuxer->current_title]; mpeg3io_seek(title->fs, demuxer->absolute_byte - title->start_byte - 1LL); //printf("1 %llx %llx\n", demuxer->absolute_byte, title->start_byte);fflush(stdout); result |= ((uint32_t)mpeg3io_read_char(title->fs)) << 24; //printf("2\n");fflush(stdout); demuxer->absolute_byte--; error = mpeg3_advance_cell(demuxer); } return error; } /* Read the packet right before the packet we're currently on. */ int mpeg3_read_prev_packet(mpeg3_demuxer_t *demuxer) { int result = 0; mpeg3_t *file = demuxer->file; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; demuxer->data_size = 0; demuxer->data_position = 0; /* * printf("mpeg3_read_prev_packet 1 %d %d %d %d %llx\n", * demuxer->total_titles, * demuxer->current_title, * title->cell_table_size, * demuxer->title_cell, * demuxer->absolute_byte);fflush(stdout); */ //printf("mpeg3_read_prev_packet 1 %d %d %llx\n", result, demuxer->current_title, mpeg3io_tell(title->fs)); /* Switch to reverse direction */ if(!demuxer->reverse) { demuxer->reverse = 1; /* Transport stream or elementary stream case */ if(file->packet_size > 0) { demuxer->absolute_byte -= file->packet_size; result = mpeg3_advance_cell(demuxer); } else /* Program stream */ { //printf("mpeg3_read_prev_packet 1 %d %llx\n", demuxer->current_title, demuxer->absolute_byte); result = prev_code(demuxer, MPEG3_PACK_START_CODE); //printf("mpeg3_read_prev_packet 2 %d %llx\n", demuxer->current_title, demuxer->absolute_byte); } } /* Go to beginning of previous packet */ do { title = demuxer->titles[demuxer->current_title]; /* * printf("mpeg3_read_prev_packet 2 %d %llx %llx\n", * demuxer->current_title, * demuxer->absolute_byte, * title->start_byte); */ /* Transport stream or elementary stream case */ if(file->packet_size > 0) { demuxer->absolute_byte -= file->packet_size; result = mpeg3_advance_cell(demuxer); } else { if(!result) result = prev_code(demuxer, MPEG3_PACK_START_CODE); } //printf("mpeg3_read_prev_packet 3 %d %llx\n", demuxer->current_title, demuxer->absolute_byte); /* Read packet and then rewind it */ title = demuxer->titles[demuxer->current_title]; if(file->is_transport_stream && !result) { result = read_transport(demuxer); if(demuxer->absolute_byte > 0) { demuxer->absolute_byte -= file->packet_size; result = mpeg3_advance_cell(demuxer); } } else if(file->is_program_stream && !result) { int64_t current_position = demuxer->absolute_byte; /* Read packet */ result = mpeg3demux_read_program(demuxer); //printf("mpeg3_read_prev_packet 5 %d %llx\n", demuxer->current_title, demuxer->absolute_byte); /* Rewind packet */ while(demuxer->absolute_byte > current_position && !result) { result = prev_code(demuxer, MPEG3_PACK_START_CODE); } //printf("mpeg3_read_prev_packet 6 %d %llx\n", demuxer->current_title, demuxer->absolute_byte); } else if(!result) { /* Elementary stream */ /* Read the packet forwards and seek back to the start */ result = mpeg3io_read_data(demuxer->data_buffer, file->packet_size, title->fs); if(!result) { demuxer->data_size = file->packet_size; result = mpeg3io_seek(title->fs, demuxer->absolute_byte); } } //printf("mpeg3_read_prev_packet 4 %d %llx\n", demuxer->current_title, demuxer->absolute_byte); }while(!result && demuxer->data_size == 0 && (demuxer->do_audio || demuxer->do_video)); //printf("mpeg3_read_prev_packet 5 %d %d %llx\n", result, demuxer->current_title, demuxer->absolute_byte);fflush(stdout); return result; } /* For audio */ int mpeg3demux_read_data(mpeg3_demuxer_t *demuxer, unsigned char *output, long size) { int result = 0; demuxer->error_flag = 0; //printf("mpeg3demux_read_data 1 %d\n", demuxer->data_position); if(demuxer->data_position >= 0) { /* Read forwards */ long i; for(i = 0; i < size && !result; ) { int fragment_size = size - i; if(fragment_size > demuxer->data_size - demuxer->data_position) fragment_size = demuxer->data_size - demuxer->data_position; memcpy(output + i, demuxer->data_buffer + demuxer->data_position, fragment_size); demuxer->data_position += fragment_size; i += fragment_size; if(i < size) { result = mpeg3_read_next_packet(demuxer); } } } else { int64_t current_position; /* Read backwards a full packet. */ /* Only good for reading less than the size of a full packet, but */ /* this routine should only be used for searching for previous markers. */ current_position = demuxer->data_position; result = mpeg3_read_prev_packet(demuxer); if(!result) demuxer->data_position = demuxer->data_size + current_position; memcpy(output, demuxer->data_buffer + demuxer->data_position, size); demuxer->data_position += size; } //printf("mpeg3demux_read_data 2\n"); demuxer->error_flag = result; return result; } unsigned char mpeg3demux_read_char_packet(mpeg3_demuxer_t *demuxer) { demuxer->error_flag = 0; if(demuxer->data_position >= demuxer->data_size) demuxer->error_flag = mpeg3_read_next_packet(demuxer); demuxer->next_char = demuxer->data_buffer[demuxer->data_position++]; return demuxer->next_char; } unsigned char mpeg3demux_read_prev_char_packet(mpeg3_demuxer_t *demuxer) { demuxer->error_flag = 0; demuxer->data_position--; if(demuxer->data_position < 0) { demuxer->error_flag = mpeg3_read_prev_packet(demuxer); if(!demuxer->error_flag) demuxer->data_position = demuxer->data_size - 1; } demuxer->next_char = demuxer->data_buffer[demuxer->data_position]; return demuxer->next_char; } int mpeg3demux_open_title(mpeg3_demuxer_t *demuxer, int title_number) { mpeg3_title_t *title; if(title_number < demuxer->total_titles) { if(demuxer->current_title >= 0) { mpeg3io_close_file(demuxer->titles[demuxer->current_title]->fs); demuxer->current_title = -1; } title = demuxer->titles[title_number]; if(mpeg3io_open_file(title->fs)) { demuxer->error_flag = 1; fprintf(stderr, "mpeg3demux_open_title %s: %s", title->fs->path, strerror(errno)); } else { demuxer->current_title = title_number; } } return demuxer->error_flag; } /* Assign program numbers to interleaved programs */ int mpeg3demux_assign_programs(mpeg3_demuxer_t *demuxer) { int current_program = 0; int current_title = 0; int title_cell = 0; double current_time; mpeg3demux_cell_t *cell; int total_programs = 1; int i, j; int program_exists, last_program_assigned = 0; int total_cells; mpeg3_title_t **titles = demuxer->titles; for(i = 0, total_cells = 0; i < demuxer->total_titles; i++) { total_cells += demuxer->titles[i]->cell_table_size; for(j = 0; j < demuxer->titles[i]->cell_table_size; j++) { cell = &demuxer->titles[i]->cell_table[j]; if(cell->program > total_programs - 1) total_programs = cell->program + 1; } } demuxer->current_program = 0; return 0; } int mpeg3demux_copy_titles(mpeg3_demuxer_t *dst, mpeg3_demuxer_t *src) { long i; mpeg3_t *file = dst->file; mpeg3_title_t *dst_title, *src_title; dst->total_titles = src->total_titles; dst->total_programs = src->total_programs; for(i = 0; i < MPEG3_MAX_STREAMS; i++) { dst->astream_table[i] = src->astream_table[i]; dst->vstream_table[i] = src->vstream_table[i]; } for(i = 0; i < src->total_titles; i++) { src_title = src->titles[i]; dst_title = dst->titles[i] = mpeg3_new_title(file, src->titles[i]->fs->path); mpeg3_copy_title(dst_title, src_title); } mpeg3demux_open_title(dst, src->current_title); dst->title_cell = 0; return 0; } /* ==================================================================== */ /* Entry points */ /* ==================================================================== */ mpeg3_demuxer_t* mpeg3_new_demuxer(mpeg3_t *file, int do_audio, int do_video, int stream_id) { mpeg3_demuxer_t *demuxer = calloc(1, sizeof(mpeg3_demuxer_t)); int i; /* The demuxer will change the default packet size for its own use. */ demuxer->file = file; demuxer->do_audio = do_audio; demuxer->do_video = do_video; /* Allocate buffer + padding */ demuxer->raw_data = calloc(1, MPEG3_RAW_SIZE); demuxer->data_buffer = calloc(1, MPEG3_RAW_SIZE); /* System specific variables */ demuxer->audio_pid = stream_id; demuxer->video_pid = stream_id; demuxer->astream = stream_id; demuxer->vstream = stream_id; demuxer->current_title = -1; demuxer->pes_audio_time = -1; demuxer->pes_video_time = -1; //printf("mpeg3_new_demuxer %f\n", demuxer->time); return demuxer; } int mpeg3_delete_demuxer(mpeg3_demuxer_t *demuxer) { int i; if(demuxer->current_title >= 0) { mpeg3io_close_file(demuxer->titles[demuxer->current_title]->fs); } for(i = 0; i < demuxer->total_titles; i++) { mpeg3_delete_title(demuxer->titles[i]); } free(demuxer->data_buffer); free(demuxer->raw_data); free(demuxer); return 0; } int mpeg3demux_eof(mpeg3_demuxer_t *demuxer) { if(demuxer->current_title >= 0) { if(mpeg3io_eof(demuxer->titles[demuxer->current_title]->fs) && demuxer->current_title >= demuxer->total_titles - 1) return 1; } return 0; } int mpeg3demux_bof(mpeg3_demuxer_t *demuxer) { if(demuxer->current_title >= 0) { if(mpeg3io_bof(demuxer->titles[demuxer->current_title]->fs) && demuxer->current_title <= 0) return 1; } return 0; } void mpeg3demux_start_reverse(mpeg3_demuxer_t *demuxer) { demuxer->reverse = 1; } void mpeg3demux_start_forward(mpeg3_demuxer_t *demuxer) { demuxer->reverse = 0; } /* Seek to absolute byte */ int mpeg3demux_seek_byte(mpeg3_demuxer_t *demuxer, int64_t byte) { mpeg3_t *file = demuxer->file; /* * int i; * for(i = 0; i < demuxer->total_titles; i++) mpeg3_dump_title(demuxer->titles[i]); */ demuxer->absolute_byte = byte; demuxer->data_position = 0; demuxer->data_size = 0; /* Get on a packet boundary only for transport streams. */ if(file->is_transport_stream && file->packet_size) { demuxer->absolute_byte -= demuxer->absolute_byte % file->packet_size; } int result = mpeg3_advance_cell(demuxer); return result; int64_t current_position; mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; demuxer->data_position = 0; demuxer->data_size = 0; demuxer->error_flag = mpeg3io_seek(title->fs, byte); if(!demuxer->error_flag && file->is_transport_stream && file->packet_size) { /* Get on a packet boundary only for transport streams. */ current_position = mpeg3io_tell(title->fs); if(byte % file->packet_size) { demuxer->error_flag |= mpeg3io_seek(title->fs, current_position - (current_position % file->packet_size)); } } demuxer->absolute_byte = title->start_byte + mpeg3io_tell(title->fs); // Get current cell for(demuxer->title_cell = 0; demuxer->title_cell < title->cell_table_size; demuxer->title_cell++) { if(title->cell_table[demuxer->title_cell].start_byte <= byte && title->cell_table[demuxer->title_cell].end_byte > byte) { break; } } if(demuxer->title_cell >= title->cell_table_size) demuxer->title_cell = title->cell_table_size - 1; return demuxer->error_flag; } double mpeg3demux_get_time(mpeg3_demuxer_t *demuxer) { return demuxer->time; } double mpeg3demux_audio_pts(mpeg3_demuxer_t *demuxer) { return demuxer->pes_audio_time; } double mpeg3demux_video_pts(mpeg3_demuxer_t *demuxer) { return demuxer->pes_video_time; } void mpeg3demux_reset_pts(mpeg3_demuxer_t *demuxer) { demuxer->pes_audio_time = -1; demuxer->pes_video_time = -1; } double mpeg3demux_scan_pts(mpeg3_demuxer_t *demuxer) { int64_t start_position = mpeg3demux_tell_byte(demuxer); int64_t end_position = start_position + MPEG3_PTS_RANGE; int64_t current_position = start_position; int result = 0; mpeg3demux_reset_pts(demuxer); while(!result && current_position < end_position && ((demuxer->do_audio && demuxer->pes_audio_time < 0) || (demuxer->do_video && demuxer->pes_video_time < 0))) { result = mpeg3_read_next_packet(demuxer); current_position = mpeg3demux_tell_byte(demuxer); } // Seek back to starting point mpeg3demux_seek_byte(demuxer, start_position); if(demuxer->do_audio) return demuxer->pes_audio_time; if(demuxer->do_video) return demuxer->pes_video_time; } int mpeg3demux_goto_pts(mpeg3_demuxer_t *demuxer, double pts) { int64_t start_position = mpeg3demux_tell_byte(demuxer); int64_t end_position = start_position + MPEG3_PTS_RANGE; int64_t current_position = start_position; int result = 0; // Search forward for nearest pts mpeg3demux_reset_pts(demuxer); while(!result && current_position < end_position) { result = mpeg3_read_next_packet(demuxer); if(demuxer->pes_audio_time > pts) break; current_position = mpeg3demux_tell_byte(demuxer); } // Search backward for nearest pts end_position = current_position - MPEG3_PTS_RANGE; mpeg3_read_prev_packet(demuxer); while(!result && current_position > end_position) { result = mpeg3_read_prev_packet(demuxer); if(demuxer->pes_audio_time < pts) break; current_position = mpeg3demux_tell_byte(demuxer); } } int64_t mpeg3demux_tell_byte(mpeg3_demuxer_t *demuxer) { return demuxer->absolute_byte; int i; int64_t result = 0; for(i = 0; i < demuxer->current_title; i++) { result += demuxer->titles[i]->total_bytes; } result += mpeg3io_tell(demuxer->titles[demuxer->current_title]->fs); return result; } int64_t mpeg3demux_movie_size(mpeg3_demuxer_t *demuxer) { int64_t result = 0; int i; for(i = 0; i < demuxer->total_titles; i++) result += demuxer->titles[i]->total_bytes; return result; } int64_t mpeg3demuxer_title_bytes(mpeg3_demuxer_t *demuxer) { mpeg3_title_t *title = demuxer->titles[demuxer->current_title]; return title->total_bytes; } mpeg3_demuxer_t* mpeg3_get_demuxer(mpeg3_t *file) { if(file->is_program_stream || file->is_transport_stream) { if(file->total_astreams) return file->atrack[0]->demuxer; else if(file->total_vstreams) return file->vtrack[0]->demuxer; } return 0; } libmpeg3-1.5.4/mpeg3demux.h0000644000175000017500000000013607742725645015710 0ustar enderender00000000000000#ifndef MPEG3DEMUX_H #define MPEG3DEMUX_H #include "mpeg3title.h" #include #endif libmpeg3-1.5.4/mpeg3dump.c0000644000175000017500000001516507766554450015536 0ustar enderender00000000000000#include "libmpeg3.h" #include "mpeg3protos.h" #include #define BUFSIZE 65536 void test_32bit_overflow(char *outfile, int (*out_counter), FILE *(*out)) { if(ftell(*out) > 0x7f000000) { char string[1024]; fclose(*out); sprintf(string, "%s%03d", outfile, ++(*out_counter)); (*out) = fopen(string, "wb"); } } int main(int argc, char *argv[]) { mpeg3_t *file; int i, j, result = 0; unsigned char *output, **output_rows; int out_counter = 0; float *audio_output_f; unsigned char *audio_output_i; long total_samples = 0; FILE *out; char outfile[1024]; int decompress_audio = 0, decompress_video = 0; int audio_track = 0; /* Print cell offsets */ int print_offsets = 1; int print_pids = 1; outfile[0] = 0; if(argc < 2) { printf( "Dump information or extract audio to a 24 bit pcm file.\n" "Example: dump -a0 outputfile.pcm take1.vob\n" ); exit(1); } for(i = 1; i < argc; i++) { if(!strncmp(argv[i], "-a", 2)) { // Check for track number if(strlen(argv[i]) > 2) { audio_track = atol(argv[i] + 2); } // Check for filename if(i + 1 < argc) { strcpy(outfile, argv[++i]); decompress_audio = 1; } else { fprintf(stderr, "-a must be paired with a filename.\n"); exit(1); } // Check if file exists if(out = fopen(outfile, "r")) { fprintf(stderr, "%s exists.\n", outfile); exit(1); } } } file = mpeg3_open(argv[argc - 1]); if(outfile[0]) { out = fopen(outfile, "wb"); } if(file) { // Audio streams fprintf(stderr, "have_mmx=%d\n", file->have_mmx); fprintf(stderr, "total_astreams=%d\n", mpeg3_total_astreams(file)); for(i = 0; i < mpeg3_total_astreams(file); i++) { fprintf(stderr, " Stream 0x%04x: channels=%d rate=%d samples=%ld format=%s\n", file->atrack[i]->demuxer->astream, mpeg3_audio_channels(file, i), mpeg3_sample_rate(file, i), mpeg3_audio_samples(file, i), mpeg3_audio_format(file, i)); if(print_offsets) { fprintf(stderr, "total_sample_offsets=%d\n", file->atrack[i]->total_sample_offsets); for(j = 0; j < file->atrack[i]->total_sample_offsets; j++) { fprintf(stderr, "%llx ", file->atrack[i]->sample_offsets[j]); if(j > 0 && !(j % 8)) fprintf(stderr, "\n"); } fprintf(stderr, "\n"); } } // Video streams fprintf(stderr, "total_vstreams=%d\n", mpeg3_total_vstreams(file)); for(i = 0; i < mpeg3_total_vstreams(file); i++) { fprintf(stderr, " Stream 0x%04x: w=%d h=%d framerate=%0.3f frames=%ld coding=%s\n", file->vtrack[i]->demuxer->vstream, mpeg3_video_width(file, i), mpeg3_video_height(file, i), mpeg3_frame_rate(file, i), mpeg3_video_frames(file, i), mpeg3_colormodel(file, i) == MPEG3_YUV420P ? "420" : "422"); if(print_offsets) { fprintf(stderr, "total_frame_offsets=%d\n", file->vtrack[i]->total_frame_offsets); for(j = 0; j < file->vtrack[i]->total_frame_offsets; j++) { fprintf(stderr, "%d=%llx ", j, file->vtrack[i]->frame_offsets[j]); if(j > 0 && !(j % 8)) fprintf(stderr, "\n"); } fprintf(stderr, "\n"); fprintf(stderr, "total_keyframe_numbers=%d\n", file->vtrack[i]->total_keyframe_numbers); for(j = 0; j < file->vtrack[i]->total_keyframe_numbers; j++) { fprintf(stderr, "%lld ", file->vtrack[i]->keyframe_numbers[j]); if(j > 0 && !(j % 8)) fprintf(stderr, "\n"); } fprintf(stderr, "\n"); } } // Titles fprintf(stderr, "total_titles=%d\n", file->demuxer->total_titles); for(i = 0; i < file->demuxer->total_titles; i++) { fprintf(stderr, " Title path=%s total_bytes=%llx cell_table_size=%d\n", file->demuxer->titles[i]->fs->path, file->demuxer->titles[i]->total_bytes, file->demuxer->titles[i]->cell_table_size); if(print_offsets) { for(j = 0; j < file->demuxer->titles[i]->cell_table_size; j++) fprintf(stderr, " Cell: %llx-%llx program=%d\n", file->demuxer->titles[i]->cell_table[j].start_byte, file->demuxer->titles[i]->cell_table[j].end_byte, file->demuxer->titles[i]->cell_table[j].program); } } // Pids if(print_pids) { mpeg3_demuxer_t *demuxer = file->demuxer; printf("Total PIDs=%d\n", demuxer->total_pids); for(i = 0; i < demuxer->total_pids; i++) { printf("0x%04x ", demuxer->pid_table[i]); } printf("\n"); } // Write audio if(decompress_audio) { mpeg3_set_cpus(file, 2); audio_output_f = malloc(BUFSIZE * sizeof(float)); audio_output_i = malloc(BUFSIZE * 3 * mpeg3_audio_channels(file, audio_track)); //printf("%d\n", mpeg3_end_of_audio(file, audio_track)); while(!mpeg3_end_of_audio(file, audio_track) && !result) { test_32bit_overflow(outfile, &out_counter, &out); for(i = 0; i < mpeg3_audio_channels(file, audio_track); i++) { if(i == 0) result = mpeg3_read_audio(file, audio_output_f, 0, i, BUFSIZE, audio_track); else result = mpeg3_reread_audio(file, audio_output_f, /* Pointer to pre-allocated buffer of floats */ 0, /* Pointer to pre-allocated buffer of int16's */ i, /* Channel to decode */ BUFSIZE, /* Number of samples to decode */ audio_track); for(j = 0; j < BUFSIZE; j++) { int sample = audio_output_f[j] * 0x7fffff; unsigned char *output_i = audio_output_i + j * 3 * mpeg3_audio_channels(file, audio_track) + i * 3; if(sample > 0x7fffff) sample = 0x7fffff; else if(sample < -0x7fffff) sample = -0x7fffff; *output_i++ = (sample & 0xff0000) >> 16; *output_i++ = (sample & 0xff00) >> 8; *output_i = sample & 0xff; } } result = !fwrite(audio_output_i, BUFSIZE * 3 * mpeg3_audio_channels(file, audio_track), 1, out); } } /* * audio_output_i = malloc(BUFSIZE * 2 * mpeg3_audio_channels(file, 0)); * mpeg3_seek_percentage(file, 0.1); * result = mpeg3_read_audio(file, 0, audio_output_i, 1, BUFSIZE, 0); */ /* * output = malloc(mpeg3_video_width(file, 0) * mpeg3_video_height(file, 0) * 3 + 4); * output_rows = malloc(sizeof(unsigned char*) * mpeg3_video_height(file, 0)); * for(i = 0; i < mpeg3_video_height(file, 0); i++) * output_rows[i] = &output[i * mpeg3_video_width(file, 0) * 3]; * printf("dump 1\n"); * mpeg3_seek_percentage(file, 0.375); * result = mpeg3_read_frame(file, * output_rows, * 0, * 0, * mpeg3_video_width(file, 0), * mpeg3_video_height(file, 0), * mpeg3_video_width(file, 0), * mpeg3_video_height(file, 0), * MPEG3_RGB888, * 0); * printf("dump 2\n"); */ mpeg3_close(file); } return 0; } libmpeg3-1.5.4/mpeg3ifo.c0000644000175000017500000004730510012061157015316 0ustar enderender00000000000000#include #include #include #include #include #include #include #include "ifo.h" #include "mpeg3private.h" #include "mpeg3protos.h" typedef struct { int64_t start_byte; int64_t end_byte; // Used in final table int program; // Used in cell play info int cell_type; // Used in cell addresses int vob_id; int cell_id; } mpeg3ifo_cell_t; typedef struct { mpeg3ifo_cell_t *cells; long total_cells; long cells_allocated; } mpeg3ifo_celltable_t; #define CADDR_HDR_LEN 8 typedef struct { u_short num : 16; // Number of Video Objects u_short unknown : 16; // don't know u_int len : 32; // length of table } cell_addr_hdr_t; typedef struct { u_int foo : 16; // ??? u_int num : 16; // number of subchannels } audio_hdr_t; #define AUDIO_HDR_LEN 4 typedef struct { u_short id : 16; // Language u_short : 16; // don't know u_int start : 32; // Start of unit } pgci_sub_t; #define PGCI_SUB_LEN 8 #define PGCI_COLOR_LEN 4 static u_int get4bytes(u_char *buf) { return bswap_32 (*((u_int32_t *)buf)); } static u_int get2bytes(u_char *buf) { return bswap_16 (*((u_int16_t *)buf)); } static int ifo_read(int fd, long pos, long count, unsigned char *data) { if((pos = lseek(fd, pos, SEEK_SET)) < 0) { perror("ifo_read"); return -1; } return read(fd, data, count); } #define OFF_PTT get4bytes (ifo->data[ID_MAT] + 0xC8) #define OFF_TITLE_PGCI get4bytes (ifo->data[ID_MAT] + 0xCC) #define OFF_MENU_PGCI get4bytes (ifo->data[ID_MAT] + 0xD0) #define OFF_TMT get4bytes (ifo->data[ID_MAT] + 0xD4) #define OFF_MENU_CELL_ADDR get4bytes (ifo->data[ID_MAT] + 0xD8) #define OFF_MENU_VOBU_ADDR_MAP get4bytes (ifo->data[ID_MAT] + 0xDC) #define OFF_TITLE_CELL_ADDR get4bytes (ifo->data[ID_MAT] + 0xE0) #define OFF_TITLE_VOBU_ADDR_MAP get4bytes (ifo->data[ID_MAT] + 0xE4) #define OFF_VMG_TSP get4bytes (ifo->data[ID_MAT] + 0xC4) #define OFF_VMG_MENU_PGCI get4bytes (ifo->data[ID_MAT] + 0xC8) #define OFF_VMG_TMT get4bytes (ifo->data[ID_MAT] + 0xD0) static int ifo_vts(ifo_t *ifo) { if(!strncmp((char*)ifo->data[ID_MAT], "DVDVIDEO-VTS", 12)) return 0; return -1; } static int ifo_vmg(ifo_t *ifo) { if(!strncmp((char*)ifo->data[ID_MAT], "DVDVIDEO-VMG", 12)) return 0; return -1; } static int ifo_table(ifo_t *ifo, unsigned long offset, unsigned long tbl_id) { unsigned char *data; unsigned long len = 0; int i; u_int32_t *ptr; if(!offset) return -1; data = (u_char *)calloc(1, DVD_VIDEO_LB_LEN); if(ifo_read(ifo->fd, ifo->pos + offset * DVD_VIDEO_LB_LEN, DVD_VIDEO_LB_LEN, data) <= 0) { perror("ifo_table"); return -1; } switch(tbl_id) { case ID_TITLE_VOBU_ADDR_MAP: case ID_MENU_VOBU_ADDR_MAP: len = get4bytes(data) + 1; break; default: { ifo_hdr_t *hdr = (ifo_hdr_t *)data; len = bswap_32(hdr->len) + 1; } } if(len > DVD_VIDEO_LB_LEN) { data = (u_char *)realloc((void *)data, len); bzero(data, len); ifo_read(ifo->fd, ifo->pos + offset * DVD_VIDEO_LB_LEN, len, data); } ifo->data[tbl_id] = data; ptr = (u_int32_t*)data; len /= 4; if(tbl_id == ID_TMT) for (i = 0; i < len; i++) ptr[i] = bswap_32(ptr[i]); return 0; } static ifo_t* ifo_open(int fd, long pos) { ifo_t *ifo; ifo = (ifo_t *)calloc(sizeof(ifo_t), 1); ifo->data[ID_MAT] = (unsigned char *)calloc(DVD_VIDEO_LB_LEN, 1); ifo->pos = pos; ifo->fd = fd; if(ifo_read(fd, pos, DVD_VIDEO_LB_LEN, ifo->data[ID_MAT]) < 0) { perror("ifo_open"); free(ifo->data[ID_MAT]); free(ifo); return NULL; } ifo->num_menu_vobs = get4bytes(ifo->data[ID_MAT] + 0xC0); ifo->vob_start = get4bytes(ifo->data[ID_MAT] + 0xC4); #ifdef DEBUG printf ("num of vobs: %x vob_start %x\n", ifo->num_menu_vobs, ifo->vob_start); #endif if(!ifo_vts(ifo)) { ifo_table(ifo, OFF_PTT, ID_PTT); ifo_table(ifo, OFF_TITLE_PGCI, ID_TITLE_PGCI); ifo_table(ifo, OFF_MENU_PGCI, ID_MENU_PGCI); ifo_table(ifo, OFF_TMT, ID_TMT); ifo_table(ifo, OFF_MENU_CELL_ADDR, ID_MENU_CELL_ADDR); ifo_table(ifo, OFF_MENU_VOBU_ADDR_MAP, ID_MENU_VOBU_ADDR_MAP); ifo_table(ifo, OFF_TITLE_CELL_ADDR, ID_TITLE_CELL_ADDR); ifo_table(ifo, OFF_TITLE_VOBU_ADDR_MAP, ID_TITLE_VOBU_ADDR_MAP); } else if(!ifo_vmg(ifo)) { ifo_table(ifo, OFF_VMG_TSP, ID_TSP); ifo_table(ifo, OFF_VMG_MENU_PGCI, ID_MENU_PGCI); ifo_table(ifo, OFF_VMG_TMT, ID_TMT); ifo_table(ifo, OFF_TITLE_CELL_ADDR, ID_TITLE_CELL_ADDR); ifo_table(ifo, OFF_TITLE_VOBU_ADDR_MAP, ID_TITLE_VOBU_ADDR_MAP); } return ifo; } static int ifo_close(ifo_t *ifo) { if(ifo->data[ID_MAT]) free(ifo->data[ID_MAT]); if(ifo->data[ID_PTT]) free(ifo->data[ID_PTT]); if(ifo->data[ID_TITLE_PGCI]) free(ifo->data[ID_TITLE_PGCI]); if(ifo->data[ID_MENU_PGCI]) free(ifo->data[ID_MENU_PGCI]); if(ifo->data[ID_TMT]) free(ifo->data[ID_TMT]); if(ifo->data[ID_MENU_CELL_ADDR]) free(ifo->data[ID_MENU_CELL_ADDR]); if(ifo->data[ID_MENU_VOBU_ADDR_MAP]) free(ifo->data[ID_MENU_VOBU_ADDR_MAP]); if(ifo->data[ID_TITLE_CELL_ADDR]) free(ifo->data[ID_TITLE_CELL_ADDR]); if(ifo->data[ID_TITLE_VOBU_ADDR_MAP]) free(ifo->data[ID_TITLE_VOBU_ADDR_MAP]); free(ifo); return 0; } static int ifo_audio(char *_hdr, char **ptr) { audio_hdr_t *hdr = (audio_hdr_t *)_hdr; if(!_hdr) return -1; *ptr = _hdr + AUDIO_HDR_LEN; return bswap_16(hdr->num); } static int pgci(ifo_hdr_t *hdr, int title, char **ptr) { pgci_sub_t *pgci_sub; *ptr = (char *) hdr; if(!*ptr) return -1; if(title > hdr->num) return -1; *ptr += IFO_HDR_LEN; pgci_sub = (pgci_sub_t *)*ptr + title; *ptr = (char *)hdr + bswap_32(pgci_sub->start); return 0; } static int program_map(char *pgc, char **ptr) { int num; *ptr = pgc; if (!pgc) return -1; *ptr += 2; num = **ptr; *ptr += 10; *ptr += 8 * 2; // AUDIO *ptr += 32 * 4; // SUBPICTURE *ptr += 8; *ptr += 16 * PGCI_COLOR_LEN; // CLUT *ptr += 2; *ptr = get2bytes((unsigned char*)*ptr) + pgc; return num; } static u_int get_cellplayinfo(u_char *pgc, u_char **ptr) { u_int num; *ptr = pgc; if (!pgc) return -1; *ptr += 3; num = **ptr; *ptr += 9; *ptr += 8 * 2; // AUDIO *ptr += 32 * 4; // SUBPICTURE *ptr += 8; *ptr += 16 * PGCI_COLOR_LEN; // CLUT *ptr += 4; *ptr = get2bytes(*ptr) + pgc; return num; } static void get_ifo_playlist(mpeg3_t *file, mpeg3_demuxer_t *demuxer) { DIR *dirstream; char directory[MPEG3_STRLEN]; char filename[MPEG3_STRLEN]; char complete_path[MPEG3_STRLEN]; char title_path[MPEG3_STRLEN]; char vob_prefix[MPEG3_STRLEN]; struct dirent *new_filename; char *ptr; int64_t total_bytes = 0; int done = 0, i; // Get titles matching ifo file mpeg3io_complete_path(complete_path, file->fs->path); mpeg3io_get_directory(directory, complete_path); mpeg3io_get_filename(filename, complete_path); strncpy(vob_prefix, filename, 6); dirstream = opendir(directory); while(new_filename = readdir(dirstream)) { if(!strncasecmp(new_filename->d_name, vob_prefix, 6)) { ptr = strrchr(new_filename->d_name, '.'); if(ptr && !strncasecmp(ptr, ".vob", 4)) { // Got a title if(atol(&new_filename->d_name[7]) > 0) { mpeg3_title_t *title; mpeg3io_joinpath(title_path, directory, new_filename->d_name); title = demuxer->titles[demuxer->total_titles++] = mpeg3_new_title(file, title_path); title->total_bytes = mpeg3io_path_total_bytes(title_path); title->start_byte = total_bytes; title->end_byte = total_bytes + title->total_bytes; total_bytes += title->total_bytes; //printf("%s\n", title_path); } } } } closedir(dirstream); // Alphabetize titles. Only problematic for guys who rip entire DVD's // to their hard drives while retaining the file structure. while(!done) { done = 1; for(i = 0; i < demuxer->total_titles - 1; i++) { if(strcmp(demuxer->titles[i]->fs->path, demuxer->titles[i + 1]->fs->path) > 0) { mpeg3_title_t *temp = demuxer->titles[i]; demuxer->titles[i] = demuxer->titles[i + 1]; demuxer->titles[i + 1] = temp; done = 0; } } } } // IFO parsing static void get_ifo_header(mpeg3_demuxer_t *demuxer, ifo_t *ifo) { int i; // Video header demuxer->vstream_table[0] = 1; // Audio header if(!ifo_vts(ifo)) { ifo_audio_t *audio; int result = 0; // Doesn't detect number of tracks. int atracks = ifo_audio((char*)ifo->data[ID_MAT] + IFO_OFFSET_AUDIO, (char**)&audio); int atracks_empirical = 0; // Collect stream id's #define TEST_START 0x1000000 #define TEST_LEN 0x1000000 mpeg3demux_open_title(demuxer, 0); mpeg3demux_seek_byte(demuxer, TEST_START); while(!result && !mpeg3demux_eof(demuxer) && mpeg3demux_tell_byte(demuxer) < TEST_START + TEST_LEN) { result = mpeg3_read_next_packet(demuxer); } mpeg3demux_seek_byte(demuxer, 0); for(i = 0; i < MPEG3_MAX_STREAMS; i++) { if(demuxer->astream_table[i]) atracks_empirical++; } // Doesn't detect PCM audio or total number of tracks /* * if(atracks && !atracks_empirical) * for(i = 0; i < atracks; i++) * { * int audio_mode = AUDIO_AC3; * switch(audio->coding_mode) * { * case 0: audio_mode = AUDIO_AC3; break; * case 1: audio_mode = AUDIO_MPEG; break; * case 2: audio_mode = AUDIO_MPEG; break; * case 3: audio_mode = AUDIO_PCM; break; * } * if(!demuxer->astream_table[i + 0x80]) demuxer->astream_table[i + 0x80] = audio_mode; * } */ } else if(!ifo_vmg(ifo)) { } } static mpeg3ifo_cell_t* append_cell(mpeg3ifo_celltable_t *table) { if(!table->cells || table->total_cells >= table->cells_allocated) { long new_allocation; mpeg3ifo_cell_t *new_cells; new_allocation = table->cells_allocated ? table->cells_allocated * 2 : 64; new_cells = calloc(1, sizeof(mpeg3ifo_cell_t) * new_allocation); if(table->cells) { memcpy(new_cells, table->cells, sizeof(mpeg3ifo_cell_t) * table->total_cells); free(table->cells); } table->cells = new_cells; table->cells_allocated = new_allocation; } return &table->cells[table->total_cells++]; } static void delete_celltable(mpeg3ifo_celltable_t *table) { if(table->cells) free(table->cells); free(table); } static void cellplayinfo(ifo_t *ifo, mpeg3ifo_celltable_t *cells) { int i, j; char *cell_hdr, *cell_hdr_start, *cell_info; ifo_hdr_t *hdr = (ifo_hdr_t*)ifo->data[ID_TITLE_PGCI]; int program_chains = bswap_16(hdr->num); long total_cells; //printf("cellplayinfo\n"); for(j = 0; j < program_chains; j++) { // Cell header pgci(hdr, j, &cell_hdr); cell_hdr_start = cell_hdr; // Unknown cell_hdr += 2; // Num programs cell_hdr += 2; // Chain Time cell_hdr += 4; // Unknown cell_hdr += 4; // Subaudio streams for(i = 0; i < 8; i++) cell_hdr += 2; // Subpictures for(i = 0; i < 32; i++) cell_hdr += 4; // Unknown for(i = 0; i < 8; i++) cell_hdr++; // Skip CLUT // Skip PGC commands // Program map if(program_map(cell_hdr_start, &cell_hdr)) ; // Cell Positions if(total_cells = get_cellplayinfo((unsigned char*)cell_hdr_start, (unsigned char**)&cell_hdr)) { //printf("cellplayinfo %d %d\n", j, total_cells); cell_info = cell_hdr; for(i = 0; i < total_cells; i++) { ifo_pgci_cell_addr_t *cell_addr = (ifo_pgci_cell_addr_t *)cell_info; long start_byte = bswap_32(cell_addr->vobu_start); long end_byte = bswap_32(cell_addr->vobu_last_end); int cell_type = cell_addr->chain_info; if(!cells->total_cells && start_byte > 0) start_byte = 0; if(!cells->total_cells || end_byte >= cells->cells[cells->total_cells - 1].end_byte) { mpeg3ifo_cell_t *cell = append_cell(cells); cell->start_byte = start_byte; cell->end_byte = end_byte; cell->cell_type = cell_type; //printf("cellplayinfo start: %llx end: %llx type: %x\n", // (int64_t)cell->start_byte * 0x800, (int64_t)cell->end_byte * 0x800, cell->cell_type); } cell_info += PGCI_CELL_ADDR_LEN; } } } } static void celladdresses(ifo_t *ifo, mpeg3ifo_celltable_t *cell_addresses) { int i; char *ptr = (char*)ifo->data[ID_TITLE_CELL_ADDR]; int total_addresses; cell_addr_hdr_t *cell_addr_hdr = (cell_addr_hdr_t*)ptr; ifo_cell_addr_t *cell_addr = (ifo_cell_addr_t*)(ptr + CADDR_HDR_LEN); int done = 0; //printf("celladdresses\n"); if(total_addresses = bswap_32(cell_addr_hdr->len) / sizeof(ifo_cell_addr_t)) { for(i = 0; i < total_addresses; i++) { mpeg3ifo_cell_t *cell; cell = append_cell(cell_addresses); cell->start_byte = (int64_t)bswap_32(cell_addr->start); cell->end_byte = (int64_t)bswap_32(cell_addr->end); cell->vob_id = bswap_16(cell_addr->vob_id); cell->cell_id = cell_addr->cell_id; /* * printf("celladdresses vob id: %x cell id: %x start: %ld end: %ld\n", * bswap_16(cell_addr->vob_id), cell_addr->cell_id, (long)cell->start_byte, (long)cell->end_byte); */ cell_addr++; } } // Sort addresses by address instead of vob id done = 0; while(!done) { done = 1; for(i = 0; i < total_addresses - 1; i++) { mpeg3ifo_cell_t *cell1, *cell2; cell1 = &cell_addresses->cells[i]; cell2 = &cell_addresses->cells[i + 1]; if(cell1->start_byte > cell2->start_byte) { mpeg3ifo_cell_t temp = *cell1; *cell1 = *cell2; *cell2 = temp; done = 0; break; } } } for(i = 0; i < total_addresses; i++) { mpeg3ifo_cell_t *cell = &cell_addresses->cells[i]; //printf("celladdresses vob id: %x cell id: %x start: %ld end: %ld\n", // cell->vob_id, cell->cell_id, (long)cell->start_byte, (long)cell->end_byte); } } static void finaltable(mpeg3ifo_celltable_t *final_cells, mpeg3ifo_celltable_t *cells, mpeg3ifo_celltable_t *cell_addresses) { int input_cell = 0, current_address = 0; int output_cell = 0; int done; int i, j; int current_vobid; // Start and end bytes of programs long program_start_byte[256], program_end_byte[256]; final_cells->total_cells = 0; final_cells->cells_allocated = cell_addresses->total_cells; final_cells->cells = calloc(1, sizeof(mpeg3ifo_cell_t) * final_cells->cells_allocated); // Assign programs to cells current_vobid = -1; for(i = cell_addresses->total_cells - 1; i >= 0; i--) { mpeg3ifo_cell_t *input = &cell_addresses->cells[i]; mpeg3ifo_cell_t *output = &final_cells->cells[i]; if(current_vobid < 0) current_vobid = input->vob_id; *output = *input; // Reduce current vobid if(input->vob_id < current_vobid) current_vobid = input->vob_id; else // Get the current program number if(input->vob_id > current_vobid) { int current_program = input->vob_id - current_vobid; output->program = current_program; // Get the last interleave by brute force for(j = i; j < cell_addresses->total_cells && cell_addresses->cells[i].cell_id == cell_addresses->cells[j].cell_id; j++) { int new_program = final_cells->cells[j].vob_id - current_vobid; if(new_program <= current_program) final_cells->cells[j].program = new_program; } } final_cells->total_cells++; } // Expand byte position and remove duplicates for(i = 0; i < final_cells->total_cells; i++) { if(i < final_cells->total_cells - 1 && final_cells->cells[i].start_byte == final_cells->cells[i + 1].start_byte) { for(j = i; j < final_cells->total_cells - 1; j++) final_cells->cells[j] = final_cells->cells[j + 1]; final_cells->total_cells--; } final_cells->cells[i].start_byte *= (int64_t)2048; final_cells->cells[i].end_byte *= (int64_t)2048; // End index seems to be inclusive final_cells->cells[i].end_byte += 2048; } return; // Debug printf("finaltable\n"); for(i = 0; i < final_cells->total_cells; i++) { printf(" vob id: %x cell id: %x start: %llx end: %llx program: %x\n", final_cells->cells[i].vob_id, final_cells->cells[i].cell_id, (int64_t)final_cells->cells[i].start_byte, (int64_t)final_cells->cells[i].end_byte, final_cells->cells[i].program); } } /* Read the title information from a ifo */ static int read_ifo(mpeg3_t *file, mpeg3_demuxer_t *demuxer, int read_cells) { int64_t last_ifo_byte = 0, first_ifo_byte = 0; mpeg3ifo_celltable_t *cells, *cell_addresses, *final_cells; int current_title = 0, current_cell = 0; int i; ifo_t *ifo; int fd = mpeg3io_get_fd(file->fs); int64_t title_start_byte = 0; int result; //printf("read_ifo 1\n"); if(!(ifo = ifo_open(fd, 0))) { fprintf(stderr, "read_ifo: Error decoding ifo.\n"); return 1; } //printf("read_ifo 1\n"); // file->packet_size = 2048; demuxer->read_all = 1; cells = calloc(1, sizeof(mpeg3ifo_celltable_t)); cell_addresses = calloc(1, sizeof(mpeg3ifo_celltable_t)); final_cells = calloc(1, sizeof(mpeg3ifo_celltable_t)); //printf("read_ifo 1\n"); get_ifo_playlist(file, demuxer); get_ifo_header(demuxer, ifo); cellplayinfo(ifo, cells); celladdresses(ifo, cell_addresses); finaltable(final_cells, cells, cell_addresses); //printf("read_ifo 2\n"); // Assign cells to titles while(final_cells && current_cell < final_cells->total_cells) { mpeg3_title_t *title; mpeg3ifo_cell_t *cell; int64_t cell_start, cell_end; int64_t length = 1; title = demuxer->titles[current_title]; cell = &final_cells->cells[current_cell]; cell_start = cell->start_byte; cell_end = cell->end_byte; //printf("read_ifo 1 %d %llx %llx %d\n", current_cell, (int64_t)cell->start_byte, (int64_t)cell->end_byte, cell->program); while(cell_start < cell_end && length) { length = cell_end - cell_start; if(cell_start + length - title_start_byte > title->total_bytes) length = title->total_bytes - cell_start + title_start_byte; // Should never fail. If it does it means the length of the cells and the // length of the titles don't match. The title lengths must match or else // the cells won't line up. if(length) { /* * printf("read_ifo title=%d start=%lx end=%lx\n", * current_title, * (long)(cell_start - title_start_byte), * (long)(cell_start - title_start_byte + length)); */ mpeg3_new_cell(title, (long)(cell_start - title_start_byte), 0, (long)(cell_start - title_start_byte + length), 0, cell->program); cell_start += length; } else { fprintf(stderr, "read_ifo: cell length and title length don't match! title=%d cell=%d cell_start=%llx cell_end=%llx.\n", current_title, current_cell, cell_start - title_start_byte, cell_end - title_start_byte); // Try this out. It works for Contact where one VOB is 0x800 bytes longer than // the cells in it but the next cell aligns perfectly with the next VOB. if(current_title < demuxer->total_titles - 1) current_cell--; } // Advance title if(cell_start - title_start_byte >= title->total_bytes && current_title < demuxer->total_titles - 1) { title_start_byte += title->total_bytes; title = demuxer->titles[++current_title]; } } current_cell++; } //printf("read_ifo 4\n"); // Look up time values for the cells // Should only be used for building a TOC /* * if(read_cells) * { * for(current_title = 0; current_title < demuxer->total_titles; current_title++) * { * mpeg3_title_t *title = demuxer->titles[current_title]; * mpeg3demux_open_title(demuxer, current_title); * * for(i = 0; i < title->cell_table_size; i++) * { * mpeg3demux_cell_t *cell = &title->cell_table[i]; * * mpeg3io_seek(title->fs, cell->start_byte); * mpeg3_read_next_packet(demuxer); * cell->start_time = demuxer->time; * * mpeg3io_seek(title->fs, cell->end_byte); * if(cell->end_byte >= title->total_bytes) * mpeg3_read_prev_packet(demuxer); * else * mpeg3_read_next_packet(demuxer); * * cell->end_time = demuxer->time; * } * } * mpeg3demux_open_title(demuxer, 0); * } */ //for(i = 0; i < demuxer->total_titles; i++) mpeg3_dump_title(demuxer->titles[i]); delete_celltable(cells); delete_celltable(cell_addresses); delete_celltable(final_cells); ifo_close(ifo); //printf("read_ifo 5\n"); mpeg3demux_assign_programs(demuxer); //printf("read_ifo 6\n"); return 0; } int mpeg3_read_ifo(mpeg3_t *file, int read_cells) { file->is_program_stream = 1; read_ifo(file, file->demuxer, read_cells); return 0; } libmpeg3-1.5.4/mpeg3io.c0000644000175000017500000001335207766700407015167 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include #include #include #include #include mpeg3_fs_t* mpeg3_new_fs(char *path) { mpeg3_fs_t *fs = calloc(1, sizeof(mpeg3_fs_t)); fs->buffer = calloc(1, MPEG3_IO_SIZE); // Force initial read fs->buffer_position = -0xffff; fs->css = mpeg3_new_css(); strcpy(fs->path, path); return fs; } int mpeg3_delete_fs(mpeg3_fs_t *fs) { mpeg3_delete_css(fs->css); free(fs->buffer); free(fs); return 0; } int mpeg3_copy_fs(mpeg3_fs_t *dst, mpeg3_fs_t *src) { strcpy(dst->path, src->path); dst->current_byte = 0; return 0; } int64_t mpeg3io_get_total_bytes(mpeg3_fs_t *fs) { struct stat64 ostat; stat64(fs->path, &ostat); fs->total_bytes = ostat.st_size; return fs->total_bytes; /* * fseek(fs->fd, 0, SEEK_END); * fs->total_bytes = ftell(fs->fd); * fseek(fs->fd, 0, SEEK_SET); * return fs->total_bytes; */ } int64_t mpeg3io_path_total_bytes(char *path) { struct stat64 st; if(stat64(path, &st) < 0) return 0; return st.st_size; } int mpeg3io_open_file(mpeg3_fs_t *fs) { /* Need to perform authentication before reading a single byte. */ mpeg3_get_keys(fs->css, fs->path); //printf("mpeg3io_open_file 1 %s\n", fs->path); if(!(fs->fd = fopen64(fs->path, "rb"))) { perror("mpeg3io_open_file"); return 1; } fs->total_bytes = mpeg3io_get_total_bytes(fs); if(!fs->total_bytes) { fclose(fs->fd); return 1; } fs->current_byte = 0; fs->buffer_position = -0xffff; return 0; } int mpeg3io_close_file(mpeg3_fs_t *fs) { if(fs->fd) fclose(fs->fd); fs->fd = 0; return 0; } int mpeg3io_read_data(unsigned char *buffer, long bytes, mpeg3_fs_t *fs) { int result = 0, i, fragment_size; for(i = 0; bytes > 0 && !result; ) { //printf("mpeg3io_read_data 1 %d\n", bytes); result = mpeg3io_sync_buffer(fs); //printf("mpeg3io_read_data 2\n"); fragment_size = MPEG3_IO_SIZE; if(fragment_size > bytes) fragment_size = bytes; if(fs->buffer_offset + fragment_size > fs->buffer_size) fragment_size = fs->buffer_size - fs->buffer_offset; memcpy(buffer + i, fs->buffer + fs->buffer_offset, fragment_size); fs->buffer_offset += fragment_size; fs->current_byte += fragment_size; i += fragment_size; bytes -= fragment_size; //printf("mpeg3io_read_data 10 %d\n", bytes); } //printf("mpeg3io_read_data 100 %d\n", bytes); return (result && bytes); } int mpeg3io_seek(mpeg3_fs_t *fs, int64_t byte) { fs->current_byte = byte; return (fs->current_byte < 0) || (fs->current_byte > fs->total_bytes); } int mpeg3io_seek_relative(mpeg3_fs_t *fs, long bytes) { fs->current_byte += bytes; return (fs->current_byte < 0) || (fs->current_byte > fs->total_bytes); } #define MIN(x, y) ((x) > (y) ? (y) : (x)) void mpeg3io_read_buffer(mpeg3_fs_t *fs) { // Special case for sequential reverse buffer. // This is only used for searching for previous codes. // Here we move a full half buffer backwards since the search normally // goes backwards and then forwards a little bit. if(fs->current_byte < fs->buffer_position && fs->current_byte >= fs->buffer_position - MPEG3_IO_SIZE / 2) { int64_t new_buffer_position = fs->current_byte - MPEG3_IO_SIZE / 2; int64_t new_buffer_size = MIN(fs->buffer_size + MPEG3_IO_SIZE / 2, MPEG3_IO_SIZE); if(new_buffer_position < 0) { new_buffer_size += new_buffer_position; new_buffer_position = 0; } // Shift existing buffer forward and calculate amount of new data needed. int remainder = new_buffer_position + new_buffer_size - fs->buffer_position; if(remainder < 0) remainder = 0; int remainder_start = new_buffer_size - remainder; int i; if(remainder) memmove(fs->buffer + remainder_start, fs->buffer, remainder); fseeko64(fs->fd, new_buffer_position, SEEK_SET); fread(fs->buffer, 1, remainder_start, fs->fd); fs->buffer_position = new_buffer_position; fs->buffer_size = new_buffer_size; fs->buffer_offset = fs->current_byte - fs->buffer_position; } else // Sequential forward buffer or random seek { int result; fs->buffer_position = fs->current_byte; fs->buffer_offset = 0; result = fseeko64(fs->fd, fs->buffer_position, SEEK_SET); fs->buffer_size = fread(fs->buffer, 1, MPEG3_IO_SIZE, fs->fd); /* * printf(__FUNCTION__ " 2 result=%d ftell=%llx buffer_position=%llx %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x\n", * result, * ftello64(fs->fd), * fs->buffer_position, * fs->buffer[0x0], * fs->buffer[0x1], * fs->buffer[0x2], * fs->buffer[0x3], * fs->buffer[0x4], * fs->buffer[0x5], * fs->buffer[0x6], * fs->buffer[0x7], * fs->buffer[0x12], * fs->buffer[0x13]); */ } } void mpeg3io_complete_path(char *complete_path, char *path) { if(path[0] != '/') { char current_dir[MPEG3_STRLEN]; getcwd(current_dir, MPEG3_STRLEN); sprintf(complete_path, "%s/%s", current_dir, path); } else strcpy(complete_path, path); } int mpeg3io_device(char *path, char *device) { struct stat64 file_st, device_st; struct mntent *mnt; FILE *fp; if(stat64(path, &file_st) < 0) { perror("mpeg3io_device"); return 1; } fp = setmntent(MOUNTED, "r"); while(fp && (mnt = getmntent(fp))) { if(stat64(mnt->mnt_fsname, &device_st) < 0) continue; if(device_st.st_rdev == file_st.st_dev) { strncpy(device, mnt->mnt_fsname, MPEG3_STRLEN); break; } } endmntent(fp); return 0; } void mpeg3io_get_directory(char *directory, char *path) { char *ptr = strrchr(path, '/'); if(ptr) { int i; for(i = 0; i < ptr - path; i++) { directory[i] = path[i]; } directory[i] = 0; } } void mpeg3io_get_filename(char *filename, char *path) { char *ptr = strrchr(path, '/'); if(!ptr) ptr = path; else ptr++; strcpy(filename, ptr); } void mpeg3io_joinpath(char *title_path, char *directory, char *new_filename) { sprintf(title_path, "%s/%s", directory, new_filename); } libmpeg3-1.5.4/mpeg3io.c.unbuffered0000644000175000017500000000735707742725645017330 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include #include #include #include mpeg3_fs_t* mpeg3_new_fs(char *path) { mpeg3_fs_t *fs = calloc(1, sizeof(mpeg3_fs_t)); fs->css = mpeg3_new_css(); strcpy(fs->path, path); return fs; } int mpeg3_delete_fs(mpeg3_fs_t *fs) { mpeg3_delete_css(fs->css); free(fs); return 0; } int mpeg3_copy_fs(mpeg3_fs_t *dst, mpeg3_fs_t *src) { strcpy(dst->path, src->path); dst->current_byte = 0; return 0; } long mpeg3io_get_total_bytes(mpeg3_fs_t *fs) { /* * struct stat st; * if(stat(fs->path, &st) < 0) return 0; * return (long)st.st_size; */ fseek(fs->fd, 0, SEEK_END); fs->total_bytes = ftell(fs->fd); fseek(fs->fd, 0, SEEK_SET); return fs->total_bytes; } long mpeg3io_path_total_bytes(char *path) { struct stat st; if(stat(path, &st) < 0) return 0; return (long)st.st_size; } int mpeg3io_open_file(mpeg3_fs_t *fs) { /* Need to perform authentication before reading a single byte. */ mpeg3_get_keys(fs->css, fs->path); if(!(fs->fd = fopen(fs->path, "rb"))) { perror("mpeg3io_open_file"); return 1; } fs->total_bytes = mpeg3io_get_total_bytes(fs); if(!fs->total_bytes) { fclose(fs->fd); return 1; } fs->current_byte = 0; return 0; } int mpeg3io_close_file(mpeg3_fs_t *fs) { if(fs->fd) fclose(fs->fd); fs->fd = 0; return 0; } int mpeg3io_read_data(unsigned char *buffer, long bytes, mpeg3_fs_t *fs) { int result = 0; result = !fread(buffer, 1, bytes, fs->fd); fs->current_byte += bytes; return (result && bytes); } int mpeg3io_device(char *path, char *device) { struct stat file_st, device_st; struct mntent *mnt; FILE *fp; if(stat(path, &file_st) < 0) { perror("mpeg3io_device"); return 1; } fp = setmntent(MOUNTED, "r"); while(fp && (mnt = getmntent(fp))) { if(stat(mnt->mnt_fsname, &device_st) < 0) continue; if(device_st.st_rdev == file_st.st_dev) { strncpy(device, mnt->mnt_fsname, MPEG3_STRLEN); break; } } endmntent(fp); return 0; } int mpeg3io_seek(mpeg3_fs_t *fs, long byte) { fs->current_byte = byte; return fseek(fs->fd, byte, SEEK_SET); } int mpeg3io_seek_relative(mpeg3_fs_t *fs, long bytes) { fs->current_byte += bytes; return fseek(fs->fd, fs->current_byte, SEEK_SET); } void mpeg3io_complete_path(char *complete_path, char *path) { if(path[0] != '/') { char current_dir[MPEG3_STRLEN]; getcwd(current_dir, MPEG3_STRLEN); sprintf(complete_path, "%s/%s", current_dir, path); } else strcpy(complete_path, path); } void mpeg3io_get_directory(char *directory, char *path) { char *ptr = strrchr(path, '/'); if(ptr) { int i; for(i = 0; i < ptr - path; i++) { directory[i] = path[i]; } directory[i] = 0; } } void mpeg3io_get_filename(char *filename, char *path) { char *ptr = strrchr(path, '/'); if(!ptr) ptr = path; else ptr++; strcpy(filename, ptr); } void mpeg3io_joinpath(char *title_path, char *directory, char *new_filename) { sprintf(title_path, "%s/%s", directory, new_filename); } /* Find end of next 4 byte code */ int mpeg3io_next_code(mpeg3_fs_t *fs, uint32_t code, int count) { uint32_t header = 0; while(header != code && !mpeg3io_eof(fs) && count > 0) { header <<= 8; header |= mpeg3io_read_char(fs); count--; } return mpeg3io_eof(fs) || count <= 0; } /* Find start of previous 4 byte code */ int mpeg3io_prev_code(mpeg3_fs_t *fs, uint32_t code, int count) { uint32_t header = 0; //printf("mpeg3io_prev_code %08x %08x %d %x %x\n", header, code, mpeg3io_bof(fs), count, fs->current_byte); while(header != code && !mpeg3io_bof(fs) && count > 0) { mpeg3io_seek_relative(fs, -1); header >>= 8; header |= ((uint32_t)mpeg3io_read_char(fs)) << 24; mpeg3io_seek_relative(fs, -1); count--; } return mpeg3io_bof(fs) || count <= 0; } libmpeg3-1.5.4/mpeg3io.h0000644000175000017500000000020707742725645015174 0ustar enderender00000000000000#ifndef MPEG3IO_H #define MPEG3IO_H #include #include #include "mpeg3css.h" #include "mpeg3private.inc" #endif libmpeg3-1.5.4/mpeg3io.h.unbuffered0000644000175000017500000000237007742725645017323 0ustar enderender00000000000000#ifndef MPEG3IO_H #define MPEG3IO_H #include #include "mpeg3css.h" #include "mpeg3private.inc" /* Filesystem structure */ typedef struct { FILE *fd; mpeg3_css_t *css; /* Encryption object */ char path[MPEG3_STRLEN]; /* Hypothetical position of file pointer */ long current_byte; long total_bytes; } mpeg3_fs_t; #define mpeg3io_tell(fs) (((mpeg3_fs_t *)(fs))->current_byte) // End of file #define mpeg3io_eof(fs) (((mpeg3_fs_t *)(fs))->current_byte >= ((mpeg3_fs_t *)(fs))->total_bytes) // Beginning of file #define mpeg3io_bof(fs) (((mpeg3_fs_t *)(fs))->current_byte < 0) #define mpeg3io_get_fd(fs) (fileno(((mpeg3_fs_t *)(fs))->fd)) #define mpeg3io_total_bytes(fs) (((mpeg3_fs_t *)(fs))->total_bytes) extern inline unsigned int mpeg3io_read_int32(mpeg3_fs_t *fs) { int a, b, c, d; unsigned int result; /* Do not fread. This breaks byte ordering. */ a = (unsigned char)fgetc(fs->fd); b = (unsigned char)fgetc(fs->fd); c = (unsigned char)fgetc(fs->fd); d = (unsigned char)fgetc(fs->fd); result = ((int)a << 24) | ((int)b << 16) | ((int)c << 8) | ((int)d); fs->current_byte += 4; return result; } extern inline unsigned int mpeg3io_read_char(mpeg3_fs_t *fs) { fs->current_byte++; return fgetc(fs->fd); } #endif libmpeg3-1.5.4/mpeg3private.h0000644000175000017500000005003310012350141016202 0ustar enderender00000000000000#ifndef MPEG3PRIVATE_H #define MPEG3PRIVATE_H #include #include #include /* Constants */ #define MPEG3_MAJOR 1 #define MPEG3_MINOR 5 #define MPEG3_RELEASE 4 #define RENDERFARM_FS_PREFIX "vfs://" #define MPEG3_FLOAT32 float #define MPEG3_TOC_PREFIX 0x544f4320 #define MPEG3_TOC_VERSION 0xff #define MPEG3_ID3_PREFIX 0x494433 #define MPEG3_IFO_PREFIX 0x44564456 #define MPEG3_IO_SIZE 0x100000 /* Bytes read by mpeg3io at a time */ //#define MPEG3_IO_SIZE 0x800 /* Bytes read by mpeg3io at a time */ #define MPEG3_RIFF_CODE 0x52494646 #define MPEG3_PROC_CPUINFO "/proc/cpuinfo" #define MPEG3_RAW_SIZE 0x100000 /* Largest possible packet */ #define MPEG3_TS_PACKET_SIZE 188 #define MPEG3_DVD_PACKET_SIZE 0x800 #define MPEG3_SYNC_BYTE 0x47 #define MPEG3_PACK_START_CODE 0x000001ba #define MPEG3_SEQUENCE_START_CODE 0x000001b3 #define MPEG3_SEQUENCE_END_CODE 0x000001b7 #define MPEG3_SYSTEM_START_CODE 0x000001bb #define MPEG3_STRLEN 1024 #define MPEG3_PIDMAX 256 /* Maximum number of PIDs in one stream */ #define MPEG3_PROGRAM_ASSOCIATION_TABLE 0x00 #define MPEG3_CONDITIONAL_ACCESS_TABLE 0x01 #define MPEG3_PACKET_START_CODE_PREFIX 0x000001 #define MPEG3_PRIVATE_STREAM_2 0xbf #define MPEG3_PADDING_STREAM 0xbe #define MPEG3_GOP_START_CODE 0x000001b8 #define MPEG3_PICTURE_START_CODE 0x00000100 #define MPEG3_EXT_START_CODE 0x000001b5 #define MPEG3_USER_START_CODE 0x000001b2 #define MPEG3_SLICE_MIN_START 0x00000101 #define MPEG3_SLICE_MAX_START 0x000001af #define MPEG3_AC3_START_CODE 0x0b77 #define MPEG3_PCM_START_CODE 0x7f7f807f #define MPEG3_MAX_CPUS 256 #define MPEG3_MAX_STREAMS 0x10000 #define MPEG3_MAX_PACKSIZE 262144 #define MPEG3_CONTIGUOUS_THRESHOLD 10 /* Positive difference before declaring timecodes discontinuous */ #define MPEG3_PROGRAM_THRESHOLD 5 /* Minimum number of seconds before interleaving programs */ #define MPEG3_SEEK_THRESHOLD 16 /* Number of frames difference before absolute seeking */ #define MPEG3_AUDIO_CHUNKSIZE 0x10000 /* Size of chunk of audio in table of contents */ #define MPEG3_LITTLE_ENDIAN ((*(uint32_t*)"x\0\0\0") & 0x000000ff) #define MPEG3_AUDIO_HISTORY 0x100000 /* Number of samples in audio history */ #define MPEG3_PTS_RANGE 0x100000 /* Range to scan for pts after byte seek */ /* Values for audio format */ #define AUDIO_UNKNOWN 0 #define AUDIO_MPEG 1 #define AUDIO_AC3 2 #define AUDIO_PCM 3 #define AUDIO_AAC 4 #define AUDIO_JESUS 5 /* Table of contents */ #define FILE_TYPE_PROGRAM 0x0 #define FILE_TYPE_TRANSPORT 0x1 #define FILE_TYPE_AUDIO 0x2 #define FILE_TYPE_VIDEO 0x3 #define STREAM_AUDIO 0x4 #define STREAM_VIDEO 0x5 #define OFFSETS_AUDIO 0x6 #define OFFSETS_VIDEO 0x7 #define ATRACK_COUNT 0x8 #define VTRACK_COUNT 0x9 #define TITLE_PATH 0x2 // CSS struct mpeg3_block { unsigned char b[5]; }; struct mpeg3_playkey { int offset; unsigned char key[5]; }; typedef struct { int encrypted; char device_path[MPEG3_STRLEN]; /* Device the file is located on */ unsigned char disk_key[MPEG3_DVD_PACKET_SIZE]; unsigned char title_key[5]; char challenge[10]; struct mpeg3_block key1; struct mpeg3_block key2; struct mpeg3_block keycheck; int varient; int fd; char path[MPEG3_STRLEN]; } mpeg3_css_t; // I/O /* Filesystem structure */ /* We buffer in MPEG3_IO_SIZE buffers. Stream IO would require back */ /* buffering a buffer since the stream must be rewound for packet headers, */ /* sequence start codes, format parsing, decryption, and mpeg3cat. */ typedef struct { FILE *fd; mpeg3_css_t *css; /* Encryption object */ char path[MPEG3_STRLEN]; unsigned char *buffer; /* Readahead buffer */ int64_t buffer_offset; /* Current buffer position */ int64_t buffer_size; /* Bytes in buffer */ int64_t buffer_position; /* Byte in file of start of buffer */ /* Hypothetical position of file pointer */ int64_t current_byte; int64_t total_bytes; } mpeg3_fs_t; // Table of contents // May get rid of time values and rename to a cell offset table. // May also get rid of end byte. typedef struct { /* Relative starting byte of cell in the title */ int64_t start_byte; /* Relative ending byte of cell in the title */ int64_t end_byte; /* Program the cell belongs to */ int program; } mpeg3demux_cell_t; typedef struct { void *file; mpeg3_fs_t *fs; /* Total bytes in title file. Critical for seeking and length. */ int64_t total_bytes; /* Absolute starting byte of the title in the stream */ int64_t start_byte; /* Absolute ending byte of the title in the stream + 1 */ int64_t end_byte; /* Timecode table */ mpeg3demux_cell_t *cell_table; int cell_table_size; /* Number of entries */ int cell_table_allocation; /* Number of available slots */ } mpeg3_title_t; // Demuxer typedef struct { /* mpeg3_t */ void* file; /* One packet. MPEG3_RAW_SIZE allocated since we don't know the packet size */ unsigned char *raw_data; /* Offset in raw_data */ int raw_offset; /* Amount loaded in last raw_data */ int raw_size; /* One packet payload */ unsigned char *data_buffer; long data_size; long data_position; /* Only one is on depending on which track owns the demultiplexer. */ int do_audio; int do_video; /* Direction of reads */ int reverse; /* Set to 1 when eof or attempt to read before beginning */ int error_flag; /* Temp variables for returning */ unsigned char next_char; int read_all; /* Info for mpeg3cat */ int64_t last_packet_start; int64_t last_packet_end; int64_t last_packet_decryption; /* Titles */ mpeg3_title_t *titles[MPEG3_MAX_STREAMS]; int total_titles; int current_title; /* Tables of every stream ID encountered */ int astream_table[MPEG3_MAX_STREAMS]; /* macro of audio format if audio */ int vstream_table[MPEG3_MAX_STREAMS]; /* 1 if video */ /* Programs */ int total_programs; int current_program; /* Cell in the current title currently used */ int title_cell; /* Absolute byte position. */ int64_t absolute_byte; int transport_error_indicator; int payload_unit_start_indicator; int pid; int transport_scrambling_control; int adaptation_field_control; int continuity_counter; int is_padding; int pid_table[MPEG3_PIDMAX]; int continuity_counters[MPEG3_PIDMAX]; int total_pids; int adaptation_fields; double time; /* Time in seconds */ int audio_pid; int video_pid; int astream; /* Video stream ID being decoded. -1 = select first ID in stream */ int vstream; /* Audio stream ID being decoded. -1 = select first ID in stream */ int aformat; /* format of the audio derived from multiplexing codes */ long program_association_tables; int table_id; int section_length; int transport_stream_id; long pes_packets; double pes_audio_time; /* Presentation Time stamps */ double pes_video_time; /* Presentation Time stamps */ } mpeg3_demuxer_t; // Bitstream // next bit in forward direction // next bit in reverse direction | // v v // | | | | | | | | | | | | | | | | | | | | | | | | | | |1|1|1|1|1|1| */ // ^ ^ // | bit_number = 1 // bfr_size = 6 typedef struct { uint32_t bfr; /* bfr = buffer for bits */ int bit_number; /* position of pointer in bfr */ int bfr_size; /* number of bits in bfr. Should always be a multiple of 8 */ void *file; /* Mpeg2 file */ mpeg3_demuxer_t *demuxer; /* Mpeg2 demuxer */ /* If the input ptr is true, data is read from it instead of the demuxer. */ unsigned char *input_ptr; } mpeg3_bits_t; // Audio #define AC3_N 512 #define MAXFRAMESIZE 4096 #define MAXFRAMESAMPLES 65536 #define HDRCMPMASK 0xfffffd00 #define SBLIMIT 32 #define SSLIMIT 18 #define SCALE_BLOCK 12 #define MPEG3AUDIO_PADDING 1024 /* Values for mode */ #define MPG_MD_STEREO 0 #define MPG_MD_JOINT_STEREO 1 #define MPG_MD_DUAL_CHANNEL 2 #define MPG_MD_MONO 3 #define MAX_AC3_FRAMESIZE 1920 * 2 + 512 extern int mpeg3_ac3_samplerates[3]; /* Exponent strategy constants */ #define MPEG3_EXP_REUSE (0) #define MPEG3_EXP_D15 (1) #define MPEG3_EXP_D25 (2) #define MPEG3_EXP_D45 (3) /* Delta bit allocation constants */ #define DELTA_BIT_REUSE (0) #define DELTA_BIT_NEW (1) #define DELTA_BIT_NONE (2) #define DELTA_BIT_RESERVED (3) // Layered decoder typedef struct { mpeg3_bits_t *stream; // Layer 3 unsigned char *bsbuf, *bsbufold; unsigned char bsspace[2][MAXFRAMESIZE + 512]; /* MAXFRAMESIZE */ int bsnum; long framesize; /* For mp3 current framesize without header. For AC3 current framesize with header. */ long prev_framesize; int channels; int samplerate; int single; int sampling_frequency_code; int error_protection; int mode; int mode_ext; int lsf; long ssize; int mpeg35; int padding; int layer; int extension; int copyright; int original; int emphasis; int bitrate; /* Static variable in synthesizer */ int bo; /* Ignore first frame after a seek */ int first_frame; float synth_stereo_buffs[2][2][0x110]; float synth_mono_buff[64]; float mp3_block[2][2][SBLIMIT * SSLIMIT]; int mp3_blc[2]; // Layer 2 int bitrate_index; struct al_table *alloc; int jsbound; int II_sblimit; unsigned int layer2_scfsi_buf[64]; } mpeg3_layer_t; // AC3 decoder typedef struct { mpeg3_bits_t *stream; int samplerate; int bitrate; int flags; int channels; void *state; /* a52_state_t */ void *output; /* sample_t */ int framesize; } mpeg3_ac3_t; // PCM decoder #define PCM_HEADERSIZE 20 typedef struct { int samplerate; int bits; int channels; int framesize; } mpeg3_pcm_t; /* IMDCT variables */ typedef struct { float real; float imag; } mpeg3_complex_t; struct al_table { short bits; short d; }; typedef struct { void* file; void* track; mpeg3_ac3_t *ac3_decoder; mpeg3_layer_t *layer_decoder; mpeg3_pcm_t *pcm_decoder; /* In order of importance */ long outscale; /* Number of current frame being decoded */ int framenum; /* Size of frame including header */ int framesize; float **output; /* Output from synthesizer in linear floats */ int output_size; /* Number of pcm samples in the buffer */ int output_allocated; /* Allocated number of samples in output */ int output_position; /* Sample position in file of start of output buffer */ /* Perform a seek to the sample */ int sample_seek; /* Perform a seek to the absolute byte */ int64_t byte_seek; /* +/- number of samples of difference between audio and video */ int seek_correction; /* Buffer containing current packet */ unsigned char packet_buffer[MAXFRAMESIZE]; /* Position in packet buffer of next byte to read */ int packet_position; } mpeg3audio_t; typedef struct { int channels; int sample_rate; mpeg3_demuxer_t *demuxer; mpeg3audio_t *audio; int current_position; int total_samples; int format; /* format of audio */ /* Pointer to master table of contents */ int64_t *sample_offsets; int total_sample_offsets; } mpeg3_atrack_t; // Video /* zig-zag scan */ extern unsigned char mpeg3_zig_zag_scan_nommx[64]; extern unsigned char mpeg3_zig_zag_scan_mmx[64]; /* alternate scan */ extern unsigned char mpeg3_alternate_scan_nommx[64]; extern unsigned char mpeg3_alternate_scan_mmx[64]; /* default intra quantization matrix */ extern unsigned char mpeg3_default_intra_quantizer_matrix[64]; /* Frame rate table must agree with the one in the encoder */ extern double mpeg3_frame_rate_table[16]; /* non-linear quantization coefficient table */ extern unsigned char mpeg3_non_linear_mquant_table[32]; #define CHROMA420 1 /* chroma_format */ #define CHROMA422 2 #define CHROMA444 3 #define TOP_FIELD 1 /* picture structure */ #define BOTTOM_FIELD 2 #define FRAME_PICTURE 3 #define SEQ_ID 1 /* extension start code IDs */ #define DISP_ID 2 #define QUANT_ID 3 #define SEQSCAL_ID 5 #define PANSCAN_ID 7 #define CODING_ID 8 #define SPATSCAL_ID 9 #define TEMPSCAL_ID 10 #define ERROR (-1) #define SC_NONE 0 /* scalable_mode */ #define SC_DP 1 #define SC_SPAT 2 #define SC_SNR 3 #define SC_TEMP 4 #define I_TYPE 1 /* picture coding type */ #define P_TYPE 2 #define B_TYPE 3 #define D_TYPE 4 #define MB_INTRA 1 /* macroblock type */ #define MB_PATTERN 2 #define MB_BACKWARD 4 #define MB_FORWARD 8 #define MB_QUANT 16 #define MB_WEIGHT 32 #define MB_CLASS4 64 #define MC_FIELD 1 /* motion_type */ #define MC_FRAME 2 #define MC_16X8 2 #define MC_DMV 3 #define MV_FIELD 0 /* mv_format */ #define MV_FRAME 1 /* Array of these feeds the slice decoders */ typedef struct { unsigned char *data; /* Buffer for holding the slice data */ int buffer_size; /* Size of buffer */ int buffer_allocation; /* Space allocated for buffer */ int current_position; /* Position in buffer */ uint32_t bits; int bits_size; pthread_mutex_t completion_lock; /* Lock slice until completion */ int done; /* Signal for slice decoder to skip */ } mpeg3_slice_buffer_t; /* Each slice decoder */ typedef struct { void *video; /* mpeg3video_t */ mpeg3_slice_buffer_t *slice_buffer; int thread_number; /* Number of this thread */ int current_buffer; /* Buffer this slice decoder is on */ int buffer_step; /* Number of buffers to skip */ int last_buffer; /* Last buffer this decoder should process */ int fault; int done; int quant_scale; int pri_brk; /* slice/macroblock */ short block[12][64]; int sparse[12]; pthread_t tid; /* ID of thread */ pthread_mutex_t input_lock, output_lock, completion_lock; } mpeg3_slice_t; typedef struct { int hour; int minute; int second; int frame; } mpeg3_timecode_t; typedef struct { void* file; void* track; /* ================================= Seeking variables ========================= */ mpeg3_bits_t *vstream; int decoder_initted; unsigned char **output_rows; /* Output frame buffer supplied by user */ int in_x, in_y, in_w, in_h, out_w, out_h; /* Output dimensions */ int row_span; int *x_table, *y_table; /* Location of every output pixel in the input */ int color_model; int want_yvu; /* Want to return a YUV frame */ char *y_output, *u_output, *v_output; /* Output pointers for a YUV frame */ mpeg3_slice_t slice_decoders[MPEG3_MAX_CPUS]; /* One slice decoder for every CPU */ int total_slice_decoders; /* Total slice decoders in use */ mpeg3_slice_buffer_t slice_buffers[MPEG3_MAX_CPUS]; /* Buffers for holding the slice data */ int total_slice_buffers; /* Total buffers in the array to be decompressed */ int slice_buffers_initialized; /* Total buffers initialized in the array */ pthread_mutex_t slice_lock; /* Lock slice array while getting the next buffer */ pthread_mutex_t test_lock; int blockreadsize; int maxframe; /* Max value of frame num to read */ int64_t byte_seek; /* Perform absolute byte seek before the next frame is read */ int frame_seek; /* Perform a frame seek before the next frame is read */ int framenum; /* Number of the next frame to be decoded */ int last_number; /* Last framenum rendered */ int found_seqhdr; int bitrate; mpeg3_timecode_t gop_timecode; /* Timecode for the last GOP header read. */ int has_gops; /* Some streams have no GOPs so try sequence start codes instead */ /* These are only available from elementary streams. */ int frames_per_gop; /* Frames per GOP after the first GOP. */ int first_gop_frames; /* Frames in the first GOP. */ int first_frame; /* Number of first frame stored in timecode */ int last_frame; /* Last frame in file */ /* ================================= Compression variables ===================== */ /* Malloced frame buffers. 2 refframes are swapped in and out. */ /* while only 1 auxframe is used. */ unsigned char *yuv_buffer[5]; /* Make YVU buffers contiguous for all frames */ unsigned char *oldrefframe[3], *refframe[3], *auxframe[3]; unsigned char *llframe0[3], *llframe1[3]; unsigned char *mpeg3_zigzag_scan_table; unsigned char *mpeg3_alternate_scan_table; // Source for the next frame presentation unsigned char **output_src; /* Pointers to frame buffers. */ unsigned char *newframe[3]; int horizontal_size, vertical_size, mb_width, mb_height; int coded_picture_width, coded_picture_height; int chroma_format, chrom_width, chrom_height, blk_cnt; int pict_type; int field_sequence; int forw_r_size, back_r_size, full_forw, full_back; int prog_seq, prog_frame; int h_forw_r_size, v_forw_r_size, h_back_r_size, v_back_r_size; int dc_prec, pict_struct, topfirst, frame_pred_dct, conceal_mv; int intravlc; int repeatfirst; int repeat_count; /* Number of times to repeat the current frame * 100 since floating point is impossible in MMX */ int current_repeat; /* Number of times the current frame has been repeated * 100 */ int secondfield; int skip_bframes; int stwc_table_index, llw, llh, hm, hn, vm, vn; int lltempref, llx0, lly0, llprog_frame, llfieldsel; int matrix_coefficients; int framerate_code; double frame_rate; int *cr_to_r, *cr_to_g, *cb_to_g, *cb_to_b; int *cr_to_r_ptr, *cr_to_g_ptr, *cb_to_g_ptr, *cb_to_b_ptr; int have_mmx; int intra_quantizer_matrix[64], non_intra_quantizer_matrix[64]; int chroma_intra_quantizer_matrix[64], chroma_non_intra_quantizer_matrix[64]; int mpeg2; int qscale_type, altscan; /* picture coding extension */ int pict_scal; /* picture spatial scalable extension */ int scalable_mode; /* sequence scalable extension */ } mpeg3video_t; typedef struct { int width; int height; double frame_rate; float aspect_ratio; mpeg3_demuxer_t *demuxer; mpeg3video_t *video; int current_position; /* Number of next frame to be played */ int total_frames; /* Total frames in the file */ /* Pointer to master table of contents */ int64_t *frame_offsets; int total_frame_offsets; int64_t *keyframe_numbers; int total_keyframe_numbers; } mpeg3_vtrack_t; // Whole thing typedef struct { /* Store entry path here */ mpeg3_fs_t *fs; /* Master title tables copied to all tracks*/ mpeg3_demuxer_t *demuxer; /* Media specific */ int total_astreams; int total_vstreams; mpeg3_atrack_t *atrack[MPEG3_MAX_STREAMS]; mpeg3_vtrack_t *vtrack[MPEG3_MAX_STREAMS]; uint64_t **frame_offsets; uint64_t **sample_offsets; uint64_t **keyframe_numbers; int *total_frame_offsets; int *total_sample_offsets; int *total_keyframe_numbers; /* Handles changes in channel count after the start of a stream */ int *channel_counts; /* Only one of these is set to 1 to specify what kind of stream we have. */ int is_transport_stream; int is_program_stream; int is_ifo_file; int is_audio_stream; /* Elemental stream */ int is_video_stream; /* Elemental stream */ /* > 0 if known otherwise determine empirically for every packet */ int packet_size; /* Type and stream for getting current absolute byte */ int last_type_read; /* 1 - audio 2 - video */ int last_stream_read; /* Number of program to play */ int program; int cpus; int have_mmx; /* Filesystem is seekable */ int seekable; /* * After byte seeking is called, this is set to -1. * The first operation to seek needs to set it to the pts of the byte seek. * Then the next operation to seek needs to match its pts to this value. */ int64_t byte_pts; } mpeg3_t; #endif libmpeg3-1.5.4/mpeg3private.inc0000644000175000017500000000006407742725645016562 0ustar enderender00000000000000#ifndef LIBMPEG3_INC #define LIBMPEG3_INC #endif libmpeg3-1.5.4/mpeg3protos.h0000644000175000017500000004332207766701652016116 0ustar enderender00000000000000#ifndef MPEG3PROTOS_H #define MPEG3PROTOS_H /* CSS */ mpeg3_css_t* mpeg3_new_css(); /* Workarounds */ int64_t mpeg3io_tell_gcc(mpeg3_fs_t *fs); double mpeg3_add_double_gcc(double x, double y); double mpeg3_divide_double_gcc(double x, double y); int64_t mpeg3_total_bytes_gcc(mpeg3_title_t *title); int64_t mpeg3io_path_total_bytes(char *path); int64_t mpeg3io_get_total_bytes(mpeg3_fs_t *fs); /* TITLE */ mpeg3_title_t* mpeg3_new_title(mpeg3_t *file, char *path); void mpeg3_new_cell(mpeg3_title_t *title, long start_byte, double start_time, long end_byte, double end_time, int program); mpeg3demux_cell_t* mpeg3_append_cell(mpeg3_demuxer_t *demuxer, mpeg3_title_t *title, long prev_byte, double prev_time, long start_byte, double start_time, int dont_store, int program); /* Called by mpeg3_open for a single file */ int mpeg3demux_create_title(mpeg3_demuxer_t *demuxer, int cell_search, FILE *toc); /* ATRACK */ mpeg3_atrack_t* mpeg3_new_atrack(mpeg3_t *file, int stream_id, int is_ac3, mpeg3_demuxer_t *demuxer, int number); int mpeg3_delete_atrack(mpeg3_t *file, mpeg3_atrack_t *atrack); /* These return 1 on failure and 0 on success */ int mpeg3_next_header(); /* VTRACK */ mpeg3_vtrack_t* mpeg3_new_vtrack(mpeg3_t *file, int stream_id, mpeg3_demuxer_t *demuxer, int number); int mpeg3_delete_vtrack(mpeg3_t *file, mpeg3_vtrack_t *vtrack); /* AUDIO */ mpeg3audio_t* mpeg3audio_new(mpeg3_t *file, mpeg3_atrack_t *track, int is_ac3); int mpeg3audio_delete(mpeg3audio_t *audio); /* Read header and store common parameters in audio structure */ int mpeg3audio_read_header(mpeg3audio_t *audio); /* Audio consists of many possible formats, each packetized into frames. */ /* Each format has a constructor, header decoder, frame decoder, and destructor. */ /* The function set is determined by the audio format. */ /* To decode audio, for each frame read the header sized number of bytes. */ /* Call the header decoder for the format. */ /* Call the frame decoder for the format. */ int mpeg3_new_decode_tables(mpeg3_layer_t *audio); int mpeg3_init_layer3(mpeg3_layer_t *audio); int mpeg3_init_layer2(mpeg3_layer_t *audio); /* Create a new layer decoder */ mpeg3_layer_t* mpeg3_new_layer(); /* Create a new ac3 decoder */ mpeg3_ac3_t* mpeg3_new_ac3(); /* Create a new pcm decoder */ mpeg3_pcm_t* mpeg3_new_pcm(); /* Delete a new layer decoder */ void mpeg3_delete_layer(mpeg3_layer_t *audio); /* Delete a new ac3 decoder */ void mpeg3_delete_ac3(mpeg3_ac3_t *audio); /* Delete a new pcm decoder */ void mpeg3_delete_pcm(mpeg3_pcm_t *audio); /* Return 1 if the data isn't a header */ int mpeg3_layer_check(unsigned char *data); int mpeg3_ac3_check(unsigned char *header); int mpeg3_pcm_check(unsigned char *header); /* These return the size of the next frame including the header */ /* or 0 if it wasn't a header. */ /* Decode a layer header */ int mpeg3_layer_header(mpeg3_layer_t *audio, unsigned char *data); /* Decode an AC3 header */ int mpeg3_ac3_header(mpeg3_ac3_t *audio, unsigned char *header); /* Decode an PCM header */ int mpeg3_pcm_header(mpeg3_pcm_t *audio, unsigned char *header); /* Reset after a seek */ void mpeg3_layer_reset(mpeg3_layer_t *audio); /* Decode a frame of layer 3 audio. */ /* The output is linear, one buffer for every channel. */ /* The user should get the channel count from one of the header commands */ /* The output must be big enough to hold the largest frame of audio */ /* These functions return the number of samples rendered */ int mpeg3audio_dolayer3(mpeg3_layer_t *audio, char *frame, int frame_size, float **output, int render); /* Decode a frame of layer 2 audio */ int mpeg3audio_dolayer2(mpeg3_layer_t *audio, char *frame, int frame_size, float **output, int render); /* Decode a frame of ac3 audio */ int mpeg3audio_doac3(mpeg3_ac3_t *audio, char *frame, int frame_size, float **output, int render); /* Decode a frame of ac3 audio */ int mpeg3audio_dopcm(mpeg3_pcm_t *audio, char *frame, int frame_size, float **output, int render); /* VIDEO */ mpeg3video_t* mpeg3video_new(mpeg3_t *file, mpeg3_vtrack_t *track); int mpeg3video_delete(mpeg3video_t *video); int mpeg3video_read_frame(mpeg3video_t *video, long frame_number, unsigned char **output_rows, int in_x, int in_y, int in_w, int in_h, int out_w, int out_h, int color_model); void mpeg3video_dump(mpeg3video_t *video); int mpeg3video_prev_code(mpeg3_demuxer_t *demuxer, unsigned int code); int mpeg3video_next_code(mpeg3_bits_t* stream, unsigned int code); void mpeg3video_toc_error(); /* FILESYSTEM */ mpeg3_fs_t* mpeg3_new_fs(char *path); int mpeg3_delete_fs(mpeg3_fs_t *fs); int mpeg3io_open_file(mpeg3_fs_t *fs); int mpeg3io_close_file(mpeg3_fs_t *fs); int mpeg3io_seek(mpeg3_fs_t *fs, int64_t byte); int mpeg3io_read_data(unsigned char *buffer, long bytes, mpeg3_fs_t *fs); // Demuxer mpeg3_demuxer_t* mpeg3_new_demuxer(mpeg3_t *file, int do_audio, int do_video, int stream_id); int mpeg3_delete_demuxer(mpeg3_demuxer_t *demuxer); mpeg3_demuxer_t* mpeg3_get_demuxer(mpeg3_t *file); int mpeg3demux_read_data(mpeg3_demuxer_t *demuxer, unsigned char *output, long size); unsigned int mpeg3demux_read_int32(mpeg3_demuxer_t *demuxer); unsigned int mpeg3demux_read_int24(mpeg3_demuxer_t *demuxer); unsigned int mpeg3demux_read_int16(mpeg3_demuxer_t *demuxer); /* Give total number of bytes in all titles */ int64_t mpeg3demux_movie_size(mpeg3_demuxer_t *demuxer); /* Give byte offset relative to start of movie */ int64_t mpeg3demux_tell_byte(mpeg3_demuxer_t *demuxer); double mpeg3demux_get_time(mpeg3_demuxer_t *demuxer); int mpeg3demux_eof(mpeg3_demuxer_t *demuxer); int mpeg3demux_bof(mpeg3_demuxer_t *demuxer); void mpeg3demux_start_reverse(mpeg3_demuxer_t *demuxer); void mpeg3demux_start_forward(mpeg3_demuxer_t *demuxer); int mpeg3demux_open_title(mpeg3_demuxer_t *demuxer, int title_number); int mpeg3demux_seek_byte(mpeg3_demuxer_t *demuxer, int64_t byte); unsigned char mpeg3demux_read_char_packet(mpeg3_demuxer_t *demuxer); unsigned char mpeg3demux_read_prev_char_packet(mpeg3_demuxer_t *demuxer); int mpeg3demux_read_program(mpeg3_demuxer_t *demuxer); /* Get last pts read */ double mpeg3demux_audio_pts(mpeg3_demuxer_t *demuxer); double mpeg3demux_video_pts(mpeg3_demuxer_t *demuxer); /* Set the last pts read to -1 for audio and video */ void mpeg3demux_reset_pts(mpeg3_demuxer_t *demuxer); /* scan forward for next pts. Used in byte seeking to synchronize */ double mpeg3demux_scan_pts(mpeg3_demuxer_t *demuxer); /* seek using sequential search to the pts given. Used in byte seeking. */ int mpeg3demux_goto_pts(mpeg3_demuxer_t *demuxer, double pts); unsigned char mpeg3demux_read_char_packet(mpeg3_demuxer_t *demuxer); unsigned char mpeg3demux_read_prev_char_packet(mpeg3_demuxer_t *demuxer); #define mpeg3demux_error(demuxer) (((mpeg3_demuxer_t *)(demuxer))->error_flag) static unsigned char mpeg3demux_read_char(mpeg3_demuxer_t *demuxer) { //printf("mpeg3demux_read_char %lx %lx\n", demuxer->data_position, demuxer->data_size); if(demuxer->data_position < demuxer->data_size) { return demuxer->data_buffer[demuxer->data_position++]; } else { return mpeg3demux_read_char_packet(demuxer); } } static unsigned char mpeg3demux_read_prev_char(mpeg3_demuxer_t *demuxer) { if(demuxer->data_position != 0) { return demuxer->data_buffer[demuxer->data_position--]; } else { return mpeg3demux_read_prev_char_packet(demuxer); } } // Bitstream mpeg3_bits_t* mpeg3bits_new_stream(mpeg3_t *file, mpeg3_demuxer_t *demuxer); int mpeg3bits_delete_stream(mpeg3_bits_t* stream); int mpeg3bits_seek_byte(mpeg3_bits_t* stream, int64_t position); int mpeg3bits_open_title(mpeg3_bits_t* stream, int title); /* Give absolute byte offset in all titles. */ int64_t mpeg3bits_tell(mpeg3_bits_t* stream); /* Reset bit bucket */ void mpeg3bits_reset(mpeg3_bits_t *stream); #define mpeg3bits_error(stream) mpeg3demux_error((stream)->demuxer) #define mpeg3bits_eof(stream) mpeg3demux_eof((stream)->demuxer) #define mpeg3bits_bof(stream) mpeg3demux_bof((stream)->demuxer) /* Read bytes backward from the file until the reverse_bits is full. */ static void mpeg3bits_fill_reverse_bits(mpeg3_bits_t* stream, int bits) { // Right justify while(stream->bit_number > 7) { stream->bfr >>= 8; stream->bfr_size -= 8; stream->bit_number -= 8; } // Insert bytes before bfr_size while(stream->bfr_size - stream->bit_number < bits) { if(stream->input_ptr) stream->bfr |= (unsigned int)(*--stream->input_ptr) << stream->bfr_size; else stream->bfr |= (unsigned int)mpeg3demux_read_prev_char(stream->demuxer) << stream->bfr_size; stream->bfr_size += 8; } } /* Read bytes forward from the file until the forward_bits is full. */ static void mpeg3bits_fill_bits(mpeg3_bits_t* stream, int bits) { while(stream->bit_number < bits) { stream->bfr <<= 8; if(stream->input_ptr) { stream->bfr |= *stream->input_ptr++; } else { stream->bfr |= mpeg3demux_read_char(stream->demuxer); } stream->bit_number += 8; stream->bfr_size += 8; if(stream->bfr_size > 32) stream->bfr_size = 32; } } /* Return 8 bits, advancing the file position. */ static unsigned int mpeg3bits_getbyte_noptr(mpeg3_bits_t* stream) { if(stream->bit_number < 8) { stream->bfr <<= 8; if(stream->input_ptr) stream->bfr |= *stream->input_ptr++; else stream->bfr |= mpeg3demux_read_char(stream->demuxer); stream->bfr_size += 8; if(stream->bfr_size > 32) stream->bfr_size = 32; return (stream->bfr >> stream->bit_number) & 0xff; } return (stream->bfr >> (stream->bit_number -= 8)) & 0xff; } static unsigned int mpeg3bits_getbit_noptr(mpeg3_bits_t* stream) { if(!stream->bit_number) { stream->bfr <<= 8; stream->bfr |= mpeg3demux_read_char(stream->demuxer); stream->bfr_size += 8; if(stream->bfr_size > 32) stream->bfr_size = 32; stream->bit_number = 7; return (stream->bfr >> 7) & 0x1; } return (stream->bfr >> (--stream->bit_number)) & (0x1); } /* Return n number of bits, advancing the file position. */ /* Use in place of flushbits */ static unsigned int mpeg3bits_getbits(mpeg3_bits_t* stream, int bits) { if(bits <= 0) return 0; mpeg3bits_fill_bits(stream, bits); return (stream->bfr >> (stream->bit_number -= bits)) & (0xffffffff >> (32 - bits)); } static unsigned int mpeg3bits_showbits24_noptr(mpeg3_bits_t* stream) { while(stream->bit_number < 24) { stream->bfr <<= 8; stream->bfr |= mpeg3demux_read_char(stream->demuxer); stream->bit_number += 8; stream->bfr_size += 8; if(stream->bfr_size > 32) stream->bfr_size = 32; } return (stream->bfr >> (stream->bit_number - 24)) & 0xffffff; } static unsigned int mpeg3bits_showbits32_noptr(mpeg3_bits_t* stream) { while(stream->bit_number < 32) { stream->bfr <<= 8; stream->bfr |= mpeg3demux_read_char(stream->demuxer); stream->bit_number += 8; stream->bfr_size += 8; if(stream->bfr_size > 32) stream->bfr_size = 32; } return stream->bfr; } static unsigned int mpeg3bits_showbits(mpeg3_bits_t* stream, int bits) { mpeg3bits_fill_bits(stream, bits); return (stream->bfr >> (stream->bit_number - bits)) & (0xffffffff >> (32 - bits)); } static unsigned int mpeg3bits_getbits_reverse(mpeg3_bits_t* stream, int bits) { unsigned int result; mpeg3bits_fill_reverse_bits(stream, bits); result = (stream->bfr >> stream->bit_number) & (0xffffffff >> (32 - bits)); stream->bit_number += bits; return result; } static unsigned int mpeg3bits_showbits_reverse(mpeg3_bits_t* stream, int bits) { unsigned int result; mpeg3bits_fill_reverse_bits(stream, bits); result = (stream->bfr >> stream->bit_number) & (0xffffffff >> (32 - bits)); return result; } // I/O // I/O must be character based so the buffer doesn't get overrun void mpeg3io_read_buffer(mpeg3_fs_t *fs); #define mpeg3io_tell(fs) (((mpeg3_fs_t *)(fs))->current_byte) // End of file #define mpeg3io_eof(fs) (((mpeg3_fs_t *)(fs))->current_byte >= ((mpeg3_fs_t *)(fs))->total_bytes) // Beginning of file #define mpeg3io_bof(fs) (((mpeg3_fs_t *)(fs))->current_byte < 0) #define mpeg3io_get_fd(fs) (fileno(((mpeg3_fs_t *)(fs))->fd)) #define mpeg3io_total_bytes(fs) (((mpeg3_fs_t *)(fs))->total_bytes) static int mpeg3io_sync_buffer(mpeg3_fs_t *fs) { // Reposition buffer offset if(fs->buffer_position + fs->buffer_offset != fs->current_byte) { fs->buffer_offset = fs->current_byte - fs->buffer_position; } // Load new buffer if(fs->current_byte < fs->buffer_position || fs->current_byte >= fs->buffer_position + fs->buffer_size) { mpeg3io_read_buffer(fs); } return !fs->buffer_size; } static unsigned int mpeg3io_read_char(mpeg3_fs_t *fs) { unsigned int result; mpeg3io_sync_buffer(fs); result = fs->buffer[fs->buffer_offset++]; fs->current_byte++; return result; } static unsigned char mpeg3io_next_char(mpeg3_fs_t *fs) { unsigned char result; mpeg3io_sync_buffer(fs); result = fs->buffer[fs->buffer_offset]; return result; } static uint32_t mpeg3io_read_int32(mpeg3_fs_t *fs) { int a, b, c, d; uint32_t result; /* Do not fread. This breaks byte ordering. */ a = mpeg3io_read_char(fs); b = mpeg3io_read_char(fs); c = mpeg3io_read_char(fs); d = mpeg3io_read_char(fs); result = (a << 24) | (b << 16) | (c << 8) | (d); return result; } static uint32_t mpeg3io_read_int24(mpeg3_fs_t *fs) { int b, c, d; uint32_t result; /* Do not fread. This breaks byte ordering. */ b = mpeg3io_read_char(fs); c = mpeg3io_read_char(fs); d = mpeg3io_read_char(fs); result = (b << 16) | (c << 8) | (d); return result; } static uint16_t mpeg3io_read_int16(mpeg3_fs_t *fs) { int c, d; uint16_t result; /* Do not fread. This breaks byte ordering. */ c = mpeg3io_read_char(fs); d = mpeg3io_read_char(fs); result = (c << 8) | (d); return result; } // More bitstream #define mpeg3slice_fillbits(buffer, nbits) \ while(((mpeg3_slice_buffer_t*)(buffer))->bits_size < (nbits)) \ { \ if(((mpeg3_slice_buffer_t*)(buffer))->current_position < ((mpeg3_slice_buffer_t*)(buffer))->buffer_size) \ { \ ((mpeg3_slice_buffer_t*)(buffer))->bits <<= 8; \ ((mpeg3_slice_buffer_t*)(buffer))->bits |= ((mpeg3_slice_buffer_t*)(buffer))->data[((mpeg3_slice_buffer_t*)(buffer))->current_position++]; \ } \ ((mpeg3_slice_buffer_t*)(buffer))->bits_size += 8; \ } #define mpeg3slice_flushbits(buffer, nbits) \ { \ mpeg3slice_fillbits((buffer), (nbits)); \ ((mpeg3_slice_buffer_t*)(buffer))->bits_size -= (nbits); \ } #define mpeg3slice_flushbit(buffer) \ { \ if(((mpeg3_slice_buffer_t*)(buffer))->bits_size) \ ((mpeg3_slice_buffer_t*)(buffer))->bits_size--; \ else \ if(((mpeg3_slice_buffer_t*)(buffer))->current_position < ((mpeg3_slice_buffer_t*)(buffer))->buffer_size) \ { \ ((mpeg3_slice_buffer_t*)(buffer))->bits = \ ((mpeg3_slice_buffer_t*)(buffer))->data[((mpeg3_slice_buffer_t*)(buffer))->current_position++]; \ ((mpeg3_slice_buffer_t*)(buffer))->bits_size = 7; \ } \ } static unsigned int mpeg3slice_getbit(mpeg3_slice_buffer_t *buffer) { if(buffer->bits_size) return (buffer->bits >> (--buffer->bits_size)) & 0x1; else if(buffer->current_position < buffer->buffer_size) { buffer->bits = buffer->data[buffer->current_position++]; buffer->bits_size = 7; return (buffer->bits >> 7) & 0x1; } return 0; } static unsigned int mpeg3slice_getbits2(mpeg3_slice_buffer_t *buffer) { if(buffer->bits_size >= 2) return (buffer->bits >> (buffer->bits_size -= 2)) & 0x3; else if(buffer->current_position < buffer->buffer_size) { buffer->bits <<= 8; buffer->bits |= buffer->data[buffer->current_position++]; buffer->bits_size += 6; return (buffer->bits >> buffer->bits_size) & 0x3; } return 0; } static unsigned int mpeg3slice_getbyte(mpeg3_slice_buffer_t *buffer) { if(buffer->bits_size >= 8) return (buffer->bits >> (buffer->bits_size -= 8)) & 0xff; else if(buffer->current_position < buffer->buffer_size) { buffer->bits <<= 8; buffer->bits |= buffer->data[buffer->current_position++]; return (buffer->bits >> buffer->bits_size) & 0xff; } return 0; } static unsigned int mpeg3slice_getbits(mpeg3_slice_buffer_t *slice_buffer, int bits) { if(bits == 1) return mpeg3slice_getbit(slice_buffer); mpeg3slice_fillbits(slice_buffer, bits); return (slice_buffer->bits >> (slice_buffer->bits_size -= bits)) & (0xffffffff >> (32 - bits)); } static unsigned int mpeg3slice_showbits16(mpeg3_slice_buffer_t *buffer) { if(buffer->bits_size >= 16) return (buffer->bits >> (buffer->bits_size - 16)) & 0xffff; else if(buffer->current_position < buffer->buffer_size) { buffer->bits <<= 16; buffer->bits_size += 16; buffer->bits |= (unsigned int)buffer->data[buffer->current_position++] << 8; buffer->bits |= buffer->data[buffer->current_position++]; return (buffer->bits >> (buffer->bits_size - 16)) & 0xffff; } return 0; } static unsigned int mpeg3slice_showbits9(mpeg3_slice_buffer_t *buffer) { if(buffer->bits_size >= 9) return (buffer->bits >> (buffer->bits_size - 9)) & 0x1ff; else if(buffer->current_position < buffer->buffer_size) { buffer->bits <<= 16; buffer->bits_size += 16; buffer->bits |= (unsigned int)buffer->data[buffer->current_position++] << 8; buffer->bits |= buffer->data[buffer->current_position++]; return (buffer->bits >> (buffer->bits_size - 9)) & 0x1ff; } return 0; } static unsigned int mpeg3slice_showbits5(mpeg3_slice_buffer_t *buffer) { if(buffer->bits_size >= 5) return (buffer->bits >> (buffer->bits_size - 5)) & 0x1f; else if(buffer->current_position < buffer->buffer_size) { buffer->bits <<= 8; buffer->bits_size += 8; buffer->bits |= buffer->data[buffer->current_position++]; return (buffer->bits >> (buffer->bits_size - 5)) & 0x1f; } return 0; } static unsigned int mpeg3slice_showbits(mpeg3_slice_buffer_t *slice_buffer, int bits) { mpeg3slice_fillbits(slice_buffer, bits); return (slice_buffer->bits >> (slice_buffer->bits_size - bits)) & (0xffffffff >> (32 - bits)); } #endif libmpeg3-1.5.4/mpeg3split.c0000644000175000017500000000601007742725645015711 0ustar enderender00000000000000#include #include #include #include "mpeg3private.inc" void copy_data(FILE *out, FILE *in, long bytes) { long fragment_size = 0x100000; char *buffer = malloc(fragment_size); long i; for(i = 0; i < bytes; i += fragment_size) { if(i + fragment_size > bytes) fragment_size = bytes - i; if(!fread(buffer, 1, fragment_size, in)) { perror("copy_data"); } if(!fwrite(buffer, 1, fragment_size, out)) { perror("copy_data"); } } free(buffer); } void split_video(char *path, long default_fragment_size) { long current_byte = 0; int result = 0; int i = 0; long total_bytes; FILE *in = fopen(path, "r"); char *sequence_hdr; long sequence_hdr_size; unsigned long header = 0; long header_start; long header_end; if(!in) { perror("split_file"); return; } fseek(in, 0, SEEK_END); total_bytes = ftell(in); fseek(in, 0, SEEK_SET); // Copy sequence header do{ header <<= 8; header = (header & 0xffffffff) | getc(in); }while(header != MPEG3_SEQUENCE_START_CODE && !feof(in)); header_start = ftell(in) - 4; do{ header <<= 8; header = (header & 0xffffffff) | getc(in); }while(header != MPEG3_GOP_START_CODE && !feof(in)); header_end = ftell(in) - 4; sequence_hdr_size = header_end - header_start; sequence_hdr = malloc(sequence_hdr_size); fseek(in, header_start, SEEK_SET); fread(sequence_hdr, 1, sequence_hdr_size, in); fseek(in, 0, SEEK_SET); while(current_byte < total_bytes && !result) { FILE *out; char outpath[1024]; long fragment_size; sprintf(outpath, "%s%02d", path, i); out = fopen(outpath, "w"); if(!out) { perror("split_file"); break; } // Default fragment size fragment_size = default_fragment_size; // Corrected fragment size if(current_byte + fragment_size >= total_bytes) { fragment_size = total_bytes - current_byte; } else { header = 0; // Get GOP header fseek(in, current_byte + fragment_size, SEEK_SET); do { fseek(in, -1, SEEK_CUR); header >>= 8; header |= ((unsigned long)fgetc(in)) << 24; fseek(in, -1, SEEK_CUR); }while(ftell(in) > 0 && header != MPEG3_GOP_START_CODE); fragment_size = ftell(in) - current_byte; fseek(in, current_byte, SEEK_SET); } // Put sequence header if(current_byte > 0) { fwrite(sequence_hdr, 1, sequence_hdr_size, out); } // Put data copy_data(out, in, fragment_size); fclose(out); i++; current_byte += fragment_size; } free(sequence_hdr); } int main(int argc, char *argv[]) { long bytes = 0; int i; if(argc < 2) { fprintf(stderr, "Split elementary streams into chunks of bytes.\n" "Usage: mpeg3split -b bytes \n"); exit(1); } for(i = 1; i < argc; i++) { if(!strcmp(argv[i], "-b")) { if(i < argc - 1) { i++; bytes = atol(argv[i]); } else { fprintf(stderr, "-b must be paired with a value\n"); exit(1); } } else if(bytes > 0) { // Split a file split_video(argv[i], bytes); } else { fprintf(stderr, "No value for bytes specified,\n"); exit(1); } } } libmpeg3-1.5.4/mpeg3title.c0000644000175000017500000001343307766715045015705 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include "mpeg3title.h" #include mpeg3_title_t* mpeg3_new_title(mpeg3_t *file, char *path) { mpeg3_title_t *title = calloc(1, sizeof(mpeg3_title_t)); title->fs = mpeg3_new_fs(path); title->file = file; return title; } int mpeg3_delete_title(mpeg3_title_t *title) { mpeg3_delete_fs(title->fs); if(title->cell_table_size) { free(title->cell_table); } free(title); return 0; } int mpeg3_copy_title(mpeg3_title_t *dst, mpeg3_title_t *src) { int i; mpeg3_copy_fs(dst->fs, src->fs); dst->total_bytes = src->total_bytes; dst->start_byte = src->start_byte; dst->end_byte = src->end_byte; if(src->cell_table_size) { dst->cell_table_allocation = src->cell_table_allocation; dst->cell_table_size = src->cell_table_size; dst->cell_table = calloc(1, sizeof(mpeg3demux_cell_t) * dst->cell_table_allocation); for(i = 0; i < dst->cell_table_size; i++) { dst->cell_table[i] = src->cell_table[i]; } } return 0; } int mpeg3_dump_title(mpeg3_title_t *title) { int i; printf("mpeg3_dump_title path %s %llx-%llx cell_table_size %d\n", title->fs->path, title->start_byte, title->end_byte, title->cell_table_size); for(i = 0; i < title->cell_table_size; i++) { printf("%llx - %llx %x\n", title->cell_table[i].start_byte, title->cell_table[i].end_byte, title->cell_table[i].program); } return 0; } // Realloc doesn't work for some reason. static void extend_cell_table(mpeg3_title_t *title) { if(!title->cell_table || title->cell_table_allocation <= title->cell_table_size) { long new_allocation; mpeg3demux_cell_t *new_table; int i; //printf("extend_cell_table 1\n"); new_allocation = title->cell_table_allocation ? title->cell_table_size * 2 : 64; new_table = calloc(1, sizeof(mpeg3demux_cell_t) * new_allocation); //printf("extend_cell_table 1\n"); memcpy(new_table, title->cell_table, sizeof(mpeg3demux_cell_t) * title->cell_table_allocation); //printf("extend_cell_table 1 %p %d %d\n", title->cell_table, title->cell_table_allocation, // (new_allocation - title->cell_table_allocation)); free(title->cell_table); title->cell_table = new_table; //printf("extend_cell_table 2\n"); title->cell_table_allocation = new_allocation; //printf("extend_cell_table 2\n"); } } void mpeg3_new_cell(mpeg3_title_t *title, long start_byte, double start_time, long end_byte, double end_time, int program) { mpeg3demux_cell_t *new_cell; extend_cell_table(title); new_cell = &title->cell_table[title->cell_table_size]; new_cell->start_byte = start_byte; new_cell->end_byte = end_byte; new_cell->program = program; title->cell_table_size++; } mpeg3demux_cell_t* mpeg3_append_cell(mpeg3_demuxer_t *demuxer, mpeg3_title_t *title, long prev_byte, double prev_time, long start_byte, double start_time, int dont_store, int program) { mpeg3demux_cell_t *new_cell, *old_cell; long i; extend_cell_table(title); /* * printf("mpeg3_append_cell 1 %d %f %d %f %d %d\n", prev_byte, * prev_time, * start_byte, * start_time, * dont_store, * program); */ new_cell = &title->cell_table[title->cell_table_size]; if(!dont_store) { new_cell->start_byte = start_byte; if(title->cell_table_size > 0) { old_cell = &title->cell_table[title->cell_table_size - 1]; old_cell->end_byte = prev_byte; } } title->cell_table_size++; return new_cell; } /* Create a title. */ /* Build a table of cells contained in the program stream. */ /* If toc is 0 just read the first and last cell. */ int mpeg3demux_create_title(mpeg3_demuxer_t *demuxer, int cell_search, FILE *toc) { int result = 0, done = 0, counter_start, counter; mpeg3_t *file = demuxer->file; int64_t next_byte, prev_byte; double next_time, prev_time, absolute_time; long i; mpeg3_title_t *title; u_int32_t test_header = 0; mpeg3demux_cell_t *cell = 0; demuxer->error_flag = 0; demuxer->read_all = 1; /* Create a single title */ if(!demuxer->total_titles) { demuxer->titles[0] = mpeg3_new_title(file, file->fs->path); demuxer->total_titles = 1; mpeg3demux_open_title(demuxer, 0); } title = demuxer->titles[0]; title->total_bytes = mpeg3io_total_bytes(title->fs); title->start_byte = 0; title->end_byte = title->total_bytes; /* Get information about file */ if(file->is_transport_stream || file->is_program_stream) { mpeg3io_seek(title->fs, 0); while(!done && !result && !mpeg3io_eof(title->fs)) { next_byte = mpeg3io_tell(title->fs); result = mpeg3_read_next_packet(demuxer); /* Just get the first bytes if not building a toc to get the stream ID's. */ if(next_byte > 0x1000000 && (!cell_search || !toc)) done = 1; //printf("mpeg3demux_create_title 1 %lld %d %p\n", next_byte, cell_search, toc); } /* Get the last cell */ if(!toc || !cell_search) { demuxer->read_all = 0; result = mpeg3io_seek(title->fs, title->total_bytes); if(!result) result = mpeg3_read_prev_packet(demuxer); } if(title->cell_table && cell) { cell->end_byte = title->total_bytes; } } mpeg3io_seek(title->fs, 0); demuxer->read_all = 0; return 0; } int mpeg3demux_print_cells(mpeg3_title_t *title, FILE *output) { mpeg3demux_cell_t *cell; mpeg3_t *file = title->file; int i; if(title->cell_table) { for(i = 0; i < title->cell_table_size; i++) { cell = &title->cell_table[i]; fprintf(output, "REGION: %ld %ld %f %f %d\n", cell->start_byte, cell->end_byte, cell->program); } } return 0; } int mpeg3demux_print_streams(mpeg3_demuxer_t *demuxer, FILE *toc) { int i; /* Print the stream information */ for(i = 0; i < MPEG3_MAX_STREAMS; i++) { if(demuxer->astream_table[i]) fprintf(toc, "ASTREAM: %d %d\n", i, demuxer->astream_table[i]); if(demuxer->vstream_table[i]) fprintf(toc, "VSTREAM: %d %d\n", i, demuxer->vstream_table[i]); } return 0; } libmpeg3-1.5.4/mpeg3title.h0000644000175000017500000000011007742725645015677 0ustar enderender00000000000000#ifndef MPEG3TITLE_H #define MPEG3TITLE_H #include "mpeg3io.h" #endif libmpeg3-1.5.4/mpeg3toc2.c0000644000175000017500000001137407743174310015422 0ustar enderender00000000000000#include "libmpeg3.h" #include "mpeg3protos.h" #define TOCVERSION 3 #define TOCVIDEO 4 int mpeg3_generate_toc(FILE *output, char *path, int timecode_search, int print_streams) { mpeg3_t *file = mpeg3_open(path); mpeg3_demuxer_t *demuxer; int i; if(file) { demuxer = mpeg3_new_demuxer(file, 0, 0, -1); if(file->is_ifo_file) { int i; mpeg3io_open_file(file->fs); mpeg3demux_read_ifo(file, demuxer, 1); mpeg3io_close_file(file->fs); for(i = 0; i < demuxer->total_titles; i++) { fprintf(output, "TOCVERSION %d\n", TOCVERSION); if(file->is_program_stream) fprintf(output, "PROGRAM_STREAM\n"); else fprintf(output, "TRANSPORT_STREAM\n"); fprintf(output, "PATH: %s\n" "SIZE: %ld\n" "PACKETSIZE: %ld\n", demuxer->titles[i]->fs->path, demuxer->titles[i]->total_bytes, file->packet_size); /* Just print the first title's streams */ if(i == 0) mpeg3demux_print_streams(demuxer, output); mpeg3demux_print_timecodes(demuxer->titles[i], output); } return 0; } else { char complete_path[MPEG3_STRLEN]; mpeg3io_complete_path(complete_path, path); fprintf(output, "TOCVERSION %d\n" "PATH: %s\n", TOCVERSION, complete_path); if(file->is_program_stream) fprintf(output, "PROGRAM_STREAM\n"); else fprintf(output, "TRANSPORT_STREAM\n"); mpeg3demux_create_title(demuxer, timecode_search, output); /* Just print the first title's streams */ if(print_streams) mpeg3demux_print_streams(demuxer, output); if(file->is_transport_stream || file->is_program_stream) { fprintf(output, "SIZE: %ld\n", demuxer->titles[demuxer->current_title]->total_bytes); fprintf(output, "PACKETSIZE: %ld\n", file->packet_size); } mpeg3demux_print_timecodes(demuxer->titles[demuxer->current_title], output); return 0; } mpeg3_delete_demuxer(demuxer); mpeg3_close(file); } return 1; } /* Read the title information from a toc */ static int read_titles(mpeg3_demuxer_t *demuxer, int version) { char string1[MPEG3_STRLEN], string2[MPEG3_STRLEN]; long start_byte, end_byte; double start_time, end_time; float program; mpeg3_title_t *title = 0; mpeg3_t *file = demuxer->file; // Eventually use IFO file to generate titles while(!feof(file->fs->fd)) { char string[1024]; int i = 0, byte; // Scanf is broken for single word lines do{ byte = fgetc(file->fs->fd); if(byte != 0 && byte != 0xd && byte != 0xa) string[i++] = byte; }while(byte != 0xd && byte != 0xa && !feof(file->fs->fd) && i < 1023); string[i] = 0; if(strlen(string)) { sscanf(string, "%s %s %ld %lf %lf %f", string1, string2, &end_byte, &start_time, &end_time, &program); //printf("read_titles 2 %d %s %s %ld %f %f %f\n", strlen(string), string1, string2, end_byte, start_time, end_time, program); if(!strncasecmp(string1, "PATH:", 5)) { //printf("read_titles 2\n"); title = demuxer->titles[demuxer->total_titles++] = mpeg3_new_title(file, string2); } else if(!strcasecmp(string1, "PROGRAM_STREAM")) { //printf("read_titles 3\n"); file->is_program_stream = 1; } else if(!strcasecmp(string1, "TRANSPORT_STREAM")) { //printf("read_titles 4\n"); file->is_transport_stream = 1; } else if(title) { mpeg3demux_cell_t *timecode; start_byte = atol(string2); //printf("read_titles 5\n"); if(!strcasecmp(string1, "REGION:")) { timecode = mpeg3_append_timecode(demuxer, title, 0, 0, 0, 0, 1, 0); //printf("mpeg3toc2 3\n"); timecode->start_byte = start_byte; //printf("mpeg3toc2 4\n"); timecode->end_byte = end_byte; timecode->start_time = start_time; timecode->end_time = end_time; timecode->program = program; /* * printf("read_title %p end: %f start: %f\n", * timecode, * timecode->end_time, * timecode->start_time); */ } else if(!strcasecmp(string1, "ASTREAM:")) demuxer->astream_table[start_byte] = end_byte; else if(!strcasecmp(string1, "VSTREAM:")) demuxer->vstream_table[start_byte] = end_byte; else if(!strcasecmp(string1, "SIZE:")) title->total_bytes = start_byte; else if(!strcasecmp(string1, "PACKETSIZE:")) file->packet_size = start_byte; //printf("read_titles 3\n"); } } } mpeg3demux_assign_programs(demuxer); mpeg3demux_open_title(demuxer, 0); return 0; } int mpeg3_read_toc(mpeg3_t *file) { char string[MPEG3_STRLEN]; int version; /* Test version number */ mpeg3io_seek(file->fs, 0); fscanf(file->fs->fd, "%s %d", string, &version); if(version != TOCVERSION && version != TOCVIDEO) return 1; switch(version) { case TOCVIDEO: file->is_video_stream = 1; break; } /* Read titles */ read_titles(file->demuxer, version); return 0; } libmpeg3-1.5.4/mpeg3toc3.c0000644000175000017500000001174207743174313015425 0ustar enderender00000000000000#include "libmpeg3.h" #include "mpeg3protos.h" #define TOCVERSION 4 #define TOCVIDEO 4 int mpeg3_generate_toc(FILE *output, char *path, int timecode_search, int print_streams) { mpeg3_t *file = mpeg3_open(path); mpeg3_demuxer_t *demuxer; int i; if(file) { demuxer = mpeg3_new_demuxer(file, 0, 0, -1); if(file->is_ifo_file) { int i; mpeg3io_open_file(file->fs); mpeg3demux_read_ifo(file, demuxer, 1); mpeg3io_close_file(file->fs); for(i = 0; i < demuxer->total_titles; i++) { fprintf(output, "TOCVERSION %d\n", TOCVERSION); if(file->is_program_stream) fprintf(output, "PROGRAM_STREAM\n"); else if(file->is_transport_stream) fprintf(output, "TRANSPORT_STREAM\n"); fprintf(output, "PATH: %s\n" "SIZE: %ld\n" "PACKETSIZE: %ld\n", demuxer->titles[i]->fs->path, demuxer->titles[i]->total_bytes, file->packet_size); /* Just print the first title's streams */ if(i == 0) mpeg3demux_print_streams(demuxer, output); mpeg3demux_print_timecodes(demuxer->titles[i], output); } return 0; } else { char complete_path[MPEG3_STRLEN]; mpeg3io_complete_path(complete_path, path); mpeg3demux_create_title(demuxer, timecode_search, output); fprintf(output, "TOCVERSION %d\n" "PATH: %s\n", TOCVERSION, complete_path); if(file->is_program_stream) fprintf(output, "PROGRAM_STREAM\n"); else if(file->is_transport_stream) fprintf(output, "TRANSPORT_STREAM\n"); else if(file->is_video_stream) fprintf(output, "VIDEO_STREAM\n"); else if(file->is_audio_stream) fprintf(output, "AUDIO_STREAM\n"); /* Just print the first title's streams */ if(print_streams) mpeg3demux_print_streams(demuxer, output); if(file->is_transport_stream || file->is_program_stream) { fprintf(output, "SIZE: %ld\n", demuxer->titles[demuxer->current_title]->total_bytes); fprintf(output, "PACKETSIZE: %ld\n", file->packet_size); } mpeg3demux_print_timecodes(demuxer->titles[demuxer->current_title], output); return 0; } mpeg3_delete_demuxer(demuxer); mpeg3_close(file); } return 1; } /* Read the title information from a toc */ static int read_titles(mpeg3_demuxer_t *demuxer, int version) { char string1[MPEG3_STRLEN], string2[MPEG3_STRLEN]; long start_byte, end_byte; double start_time, end_time; float program; mpeg3_title_t *title = 0; mpeg3_t *file = demuxer->file; // Eventually use IFO file to generate titles while(!feof(file->fs->fd)) { char string[1024]; int i = 0, byte; // Scanf is broken for single word lines do{ byte = fgetc(file->fs->fd); if(byte != 0 && byte != 0xd && byte != 0xa) string[i++] = byte; }while(byte != 0xd && byte != 0xa && !feof(file->fs->fd) && i < 1023); string[i] = 0; if(strlen(string)) { sscanf(string, "%s %s %ld %lf %lf %f", string1, string2, &end_byte, &start_time, &end_time, &program); //printf("read_titles 2 %d %s %s %ld %f %f %f\n", strlen(string), string1, string2, end_byte, start_time, end_time, program); if(!strncasecmp(string1, "PATH:", 5)) { //printf("read_titles 2\n"); title = demuxer->titles[demuxer->total_titles++] = mpeg3_new_title(file, string2); } else if(!strcasecmp(string1, "PROGRAM_STREAM")) { //printf("read_titles 3\n"); file->is_program_stream = 1; } else if(!strcasecmp(string1, "TRANSPORT_STREAM")) { //printf("read_titles 4\n"); file->is_transport_stream = 1; } else if(title) { mpeg3demux_cell_t *timecode; start_byte = atol(string2); //printf("read_titles 5\n"); if(!strcasecmp(string1, "REGION:")) { timecode = mpeg3_append_timecode(demuxer, title, 0, 0, 0, 0, 1, 0); //printf("mpeg3toc2 3\n"); timecode->start_byte = start_byte; //printf("mpeg3toc2 4\n"); timecode->end_byte = end_byte; timecode->start_time = start_time; timecode->end_time = end_time; timecode->program = program; /* * printf("read_title %p end: %f start: %f\n", * timecode, * timecode->end_time, * timecode->start_time); */ } else if(!strcasecmp(string1, "ASTREAM:")) demuxer->astream_table[start_byte] = end_byte; else if(!strcasecmp(string1, "VSTREAM:")) demuxer->vstream_table[start_byte] = end_byte; else if(!strcasecmp(string1, "SIZE:")) title->total_bytes = start_byte; else if(!strcasecmp(string1, "PACKETSIZE:")) file->packet_size = start_byte; //printf("read_titles 3\n"); } } } mpeg3demux_assign_programs(demuxer); mpeg3demux_open_title(demuxer, 0); return 0; } int mpeg3_read_toc(mpeg3_t *file) { char string[MPEG3_STRLEN]; int version; /* Test version number */ mpeg3io_seek(file->fs, 0); fscanf(file->fs->fd, "%s %d", string, &version); if(version != TOCVERSION && version != TOCVIDEO) return 1; switch(version) { case TOCVIDEO: file->is_video_stream = 1; break; } /* Read titles */ read_titles(file->demuxer, version); return 0; } libmpeg3-1.5.4/mpeg3toc.c0000644000175000017500000002770410012061157015327 0ustar enderender00000000000000#include "libmpeg3.h" #include "mpeg3protos.h" #include #include #include #include #include /* * Generate table of frame and sample offsets for editing. */ #define INIT_VECTORS(data, size, allocation, tracks) \ { \ int k; \ data = calloc(1, sizeof(int64_t*) * tracks); \ size = calloc(1, sizeof(int*) * tracks); \ allocation = calloc(1, sizeof(int*) * tracks); \ \ for(k = 0; k < tracks; k++) \ { \ allocation[k] = 0x100; \ data[k] = calloc(1, sizeof(int64_t) * allocation[k]); \ } \ } #if 1 #define APPEND_VECTOR(data, size, allocation, track, value) \ { \ uint64_t **track_data = &(data)[(track)]; \ int *track_allocation = &(allocation)[(track)]; \ int *track_size = &(size)[(track)]; \ \ if(!(*track_data) || (*track_allocation) <= (*track_size)) \ { \ int64_t *new_data = calloc(1, sizeof(int64_t) * (*track_allocation) * 2); \ \ if((*track_data)) \ { \ memcpy(new_data, (*track_data), sizeof(int64_t) * (*track_allocation)); \ free((*track_data)); \ } \ (*track_allocation) *= 2; \ (*track_data) = new_data; \ } \ \ (*track_data)[(*track_size)++] = (value); \ } #else #define APPEND_VECTOR(data, size, allocation, track, value) \ ; #endif #define DELETE_VECTORS(data, size, allocation, tracks) \ { \ int k; \ for(k = 0; k < tracks; k++) if(data[k]) free(data[k]); \ free(data); \ } #define PUT_INT32(x) \ { \ if(MPEG3_LITTLE_ENDIAN) \ { \ fputc(((unsigned char*)&x)[3], output); \ fputc(((unsigned char*)&x)[2], output); \ fputc(((unsigned char*)&x)[1], output); \ fputc(((unsigned char*)&x)[0], output); \ } \ else \ { \ fputc(((unsigned char*)&x)[0], output); \ fputc(((unsigned char*)&x)[1], output); \ fputc(((unsigned char*)&x)[2], output); \ fputc(((unsigned char*)&x)[3], output); \ } \ } #define PUT_INT64(x) \ { \ if(MPEG3_LITTLE_ENDIAN) \ { \ fputc(((unsigned char*)&x)[7], output); \ fputc(((unsigned char*)&x)[6], output); \ fputc(((unsigned char*)&x)[5], output); \ fputc(((unsigned char*)&x)[4], output); \ fputc(((unsigned char*)&x)[3], output); \ fputc(((unsigned char*)&x)[2], output); \ fputc(((unsigned char*)&x)[1], output); \ fputc(((unsigned char*)&x)[0], output); \ } \ else \ { \ fwrite(&x, 1, 8, output); \ } \ } int main(int argc, char *argv[]) { struct stat st; int i, j, l; char *src = 0, *dst = 0; int astream_override = -1; if(argc < 3) { fprintf(stderr, "Create a table of contents for a DVD or mpeg stream.\n" " Usage: [-a audio streams] mpeg3toc \n" "\n" " -a override the number of audio streams to scan. Must be less than\n" "the total number of audio streams.\n" "\n" " The path should be absolute unless you plan\n" " to always run your movie editor from the same directory\n" " as the filename. For renderfarms the filesystem prefix\n" " should be / and the movie directory mounted under the same\n" " directory on each node.\n" "Example: mpeg3toc /cd2/video_ts/vts_01_0.ifo titanic.toc\n"); exit(1); } for(i = 1; i < argc; i++) { if(!strcmp(argv[i], "-a")) { if(i < argc - 1) { astream_override = atoi(argv[i + 1]); if(astream_override < 0) { fprintf(stderr, "Total audio streams may not be negative\n"); exit(1); } else { fprintf(stderr, "Using first %d audio streams.\n", astream_override); } i++; } else { fprintf(stderr, "-a requires an argument.\n"); exit(1); } } else if(!src) { src = argv[i]; } else if(!dst) { dst = argv[i]; } else { fprintf(stderr, "Ignoring argument \"%s\"\n", argv[i]); } } if(!src) { fprintf(stderr, "source path not supplied.\n"); exit(1); } if(!dst) { fprintf(stderr, "source path not supplied.\n"); exit(1); } stat(src, &st); if(!st.st_size) { fprintf(stderr, "%s is 0 length. Skipping\n", src); } else { int64_t size; int vtracks; int atracks; mpeg3_t *input; uint64_t **frame_offsets; uint64_t **keyframe_numbers; uint64_t **sample_offsets; int *total_frame_offsets; int *total_sample_offsets; int *total_keyframe_numbers; int *frame_offset_allocation; int *sample_offset_allocation; int *keyframe_numbers_allocation; int done = 0; double sample_rate; double frame_rate; FILE *output; int total_samples = 0; int total_frames = 0; int rewind = 1; //printf(__FUNCTION__ " 1\n"); input = mpeg3_open(src); //printf(__FUNCTION__ " 2\n"); vtracks = mpeg3_total_vstreams(input); atracks = mpeg3_total_astreams(input); if(astream_override >= 0) atracks = astream_override; if(atracks) sample_rate = mpeg3_sample_rate(input, 0); if(vtracks) frame_rate = mpeg3_frame_rate(input, 0); //printf(__FUNCTION__ " 3\n"); // Handle titles INIT_VECTORS(frame_offsets, total_frame_offsets, frame_offset_allocation, vtracks); INIT_VECTORS(keyframe_numbers, total_keyframe_numbers, keyframe_numbers_allocation, vtracks); INIT_VECTORS(sample_offsets, total_sample_offsets, sample_offset_allocation, atracks); //printf(__FUNCTION__ " 4\n"); while(!done) { int sample_count = MPEG3_AUDIO_CHUNKSIZE; int frame_count; int have_audio = 0; int have_video = 0; int64_t title_number = 0; // Audio section // Store current position and read sample_count from each atrack for(j = 0; j < atracks; j++) { //printf(__FUNCTION__ " 3 %d\n", total_sample_offsets[j]); if(rewind) { mpeg3_demuxer_t *demuxer = input->atrack[j]->demuxer; mpeg3demux_seek_byte(demuxer, 0); } if(!mpeg3_end_of_audio(input, j)) { // Don't want to maintain separate vectors for offset and title. int64_t position = mpeg3demux_tell_byte(input->atrack[j]->demuxer); int64_t result; if(position < MPEG3_IO_SIZE) position = MPEG3_IO_SIZE; // result = (title_number << 56) | (position - MPEG3_IO_SIZE); result = position; have_audio = 1; APPEND_VECTOR(sample_offsets, total_sample_offsets, sample_offset_allocation, j, result); //printf(__FUNCTION__ " 6 %d\n", j); // Throw away samples mpeg3_read_audio(input, 0, 0, 0, sample_count, /* Number of samples to decode */ j); //printf(__FUNCTION__ " 7 %d\n", total_sample_offsets[j]); } if(j == atracks - 1) { total_samples += sample_count; printf("Audio: title=%lld total_samples=%d ", title_number, total_samples); } } //printf(__FUNCTION__ " 8\n"); if(have_audio) { frame_count = (int)((double)total_samples / sample_rate * frame_rate + 0.5) - total_frames; } else { frame_count = 1; } //printf(__FUNCTION__ " 9 %d\n", vtracks); // Video section for(j = 0; j < vtracks; j++) { mpeg3video_t *video = input->vtrack[j]->video; mpeg3_demuxer_t *demuxer = input->vtrack[j]->demuxer; if(rewind) { mpeg3demux_seek_byte(demuxer, 0); } for(l = 0; l < frame_count; l++) { if(!mpeg3_end_of_video(input, j)) { int64_t position = mpeg3demux_tell_byte(demuxer); int64_t result; uint32_t code = 0; int got_top = 0; int got_bottom = 0; int got_keyframe = 0; int fields = 0; if(position < MPEG3_IO_SIZE) position = MPEG3_IO_SIZE; // result = (title_number << 56) | (position - MPEG3_IO_SIZE); result = position; have_video = 1; //printf("%llx\n", position); // Store offset of every frame in table APPEND_VECTOR(frame_offsets, total_frame_offsets, frame_offset_allocation, j, result); // Search for next frame start. if(total_frame_offsets[j] == 1) { // Assume first frame is an I-frame and put its number in the keyframe number // table. APPEND_VECTOR(keyframe_numbers, total_keyframe_numbers, keyframe_numbers_allocation, j, 0); // Skip the first frame. mpeg3video_get_header(video, 0); video->current_repeat += 100; } // Get next frame do { mpeg3video_get_header(video, 0); video->current_repeat += 100; if(video->pict_struct == TOP_FIELD) { got_top = 1; } else if(video->pict_struct == BOTTOM_FIELD) { got_bottom = 1; } else if(video->pict_struct == FRAME_PICTURE) { got_top = got_bottom = 1; } fields++; // The way we do it, the I frames have the top field but both the I frame and // subsequent P frame make the keyframe. if(video->pict_type == I_TYPE) got_keyframe = 1; }while(!mpeg3_end_of_video(input, j) && !got_bottom && total_frame_offsets[j] > 1); // Store number of a keyframe in the keyframe number table if(got_keyframe) APPEND_VECTOR(keyframe_numbers, total_keyframe_numbers, keyframe_numbers_allocation, j, total_frame_offsets[j] - 1); if(j == vtracks - 1 && l == frame_count - 1) { total_frames += frame_count; printf("Video: title=%lld total_frames=%d ", title_number, total_frames); } } } } if(!have_audio && !have_video) done = 1; printf("\r"); fflush(stdout); /* * if(total_frames > 10000) * { * printf("\n"); * return 0; * } */ rewind = 0; } output = fopen(dst, "w"); // Write file type fputc('T', output); fputc('O', output); fputc('C', output); fputc(' ', output); // Write version fputc(MPEG3_TOC_VERSION, output); if(input->is_program_stream) { fputc(FILE_TYPE_PROGRAM, output); } else if(input->is_transport_stream) { fputc(FILE_TYPE_TRANSPORT, output); } else if(input->is_audio_stream) { fputc(FILE_TYPE_AUDIO, output); } else if(input->is_video_stream) { fputc(FILE_TYPE_VIDEO, output); } // Write stream ID's // Only program and transport streams have these for(i = 0; i < MPEG3_MAX_STREAMS; i++) { if(input->demuxer->astream_table[i]) { fputc(STREAM_AUDIO, output); PUT_INT32(i); PUT_INT32(input->demuxer->astream_table[i]); } if(input->demuxer->vstream_table[i]) { fputc(STREAM_VIDEO, output); PUT_INT32(i); PUT_INT32(input->demuxer->vstream_table[i]); } } // Write titles for(i = 0; i < input->demuxer->total_titles; i++) { // Path fputc(TITLE_PATH, output); fprintf(output, input->demuxer->titles[i]->fs->path); fputc(0, output); // Total bytes PUT_INT64(input->demuxer->titles[i]->total_bytes); // Byte offsets of cells PUT_INT32(input->demuxer->titles[i]->cell_table_size); for(j = 0; j < input->demuxer->titles[i]->cell_table_size; j++) { PUT_INT64(input->demuxer->titles[i]->cell_table[j].start_byte); PUT_INT64(input->demuxer->titles[i]->cell_table[j].end_byte); PUT_INT32(input->demuxer->titles[i]->cell_table[j].program); } } fputc(ATRACK_COUNT, output); PUT_INT32(atracks); fputc(VTRACK_COUNT, output); PUT_INT32(vtracks); // Audio streams for(j = 0; j < atracks; j++) { int channels = mpeg3_audio_channels(input, j); PUT_INT32(channels); PUT_INT32(total_sample_offsets[j]); for(i = 0; i < total_sample_offsets[j]; i++) { PUT_INT64(sample_offsets[j][i]); //printf("Audio: offset=%016llx\n", sample_offsets[j][i]); } } // Video streams for(j = 0; j < vtracks; j++) { PUT_INT32(total_frame_offsets[j]); for(i = 0; i < total_frame_offsets[j]; i++) { PUT_INT64(frame_offsets[j][i]); //printf("Video: offset=%016llx\n", frame_offsets[j][i]); } PUT_INT32(total_keyframe_numbers[j]); for(i = 0; i < total_keyframe_numbers[j]; i++) { PUT_INT64(keyframe_numbers[j][i]); //printf("Video: keyframe=%lld\n", keyframe_numbers[j][i]); } } DELETE_VECTORS(frame_offsets, total_frame_offsets, frame_offset_allocation, vtracks); DELETE_VECTORS(keyframe_numbers, total_keyframe_numbers, keyframe_numbers_allocation, vtracks); DELETE_VECTORS(sample_offsets, total_sample_offsets, sample_offset_allocation, atracks); mpeg3_close(input); fclose(output); } return 0; } libmpeg3-1.5.4/mpeg3vtrack.c0000644000175000017500000000261507742725645016057 0ustar enderender00000000000000#include "libmpeg3.h" #include "mpeg3protos.h" #include mpeg3_vtrack_t* mpeg3_new_vtrack(mpeg3_t *file, int stream_id, mpeg3_demuxer_t *demuxer, int number) { int result = 0; mpeg3_vtrack_t *new_vtrack; //printf("mpeg3_new_vtrack 1\n"); new_vtrack = calloc(1, sizeof(mpeg3_vtrack_t)); new_vtrack->demuxer = mpeg3_new_demuxer(file, 0, 1, stream_id); if(new_vtrack->demuxer) mpeg3demux_copy_titles(new_vtrack->demuxer, demuxer); new_vtrack->current_position = 0; //printf("mpeg3_new_vtrack 10\n"); // Copy pointers if(file->frame_offsets) { new_vtrack->frame_offsets = file->frame_offsets[number]; new_vtrack->total_frame_offsets = file->total_frame_offsets[number]; new_vtrack->keyframe_numbers = file->keyframe_numbers[number]; new_vtrack->total_keyframe_numbers = file->total_keyframe_numbers[number]; } //printf("mpeg3_new_vtrack 20\n"); //printf("mpeg3_new_vtrack %llx\n", mpeg3demux_tell(new_vtrack->demuxer)); /* Get information about the track here. */ new_vtrack->video = mpeg3video_new(file, new_vtrack); if(!new_vtrack->video) { /* Failed */ mpeg3_delete_vtrack(file, new_vtrack); new_vtrack = 0; } //printf("mpeg3_new_vtrack 100\n"); return new_vtrack; } int mpeg3_delete_vtrack(mpeg3_t *file, mpeg3_vtrack_t *vtrack) { if(vtrack->video) mpeg3video_delete(vtrack->video); if(vtrack->demuxer) mpeg3_delete_demuxer(vtrack->demuxer); free(vtrack); return 0; } libmpeg3-1.5.4/mpeg3vtrack.h0000644000175000017500000000015507742725645016061 0ustar enderender00000000000000#ifndef MPEG3_VTRACK_H #define MPEG3_VTRACK_H #include "mpeg3demux.h" #include "video/mpeg3video.h" #endif libmpeg3-1.5.4/timecode.h0000644000175000017500000000005607742725645015424 0ustar enderender00000000000000#ifndef TIMECODE_H #define TIMECODE_H #endif libmpeg3-1.5.4/video/0000755000175000017500000000000010012353221014532 5ustar enderender00000000000000libmpeg3-1.5.4/video/seek.c.bak0000644000175000017500000002426107743706457016424 0ustar enderender00000000000000#include "../mpeg3private.h" #include "../mpeg3protos.h" #include "mpeg3video.h" #include #include unsigned int mpeg3bits_next_startcode(mpeg3_bits_t* stream) { /* Perform forwards search */ mpeg3bits_byte_align(stream); /* * printf("mpeg3bits_next_startcode 1 %lld %lld\n", * stream->demuxer->titles[0]->fs->current_byte, * stream->demuxer->titles[0]->fs->total_bytes); * */ //mpeg3_read_next_packet(stream->demuxer); //printf("mpeg3bits_next_startcode 2 %d %d\n", // stream->demuxer->titles[0]->fs->current_byte, // stream->demuxer->titles[0]->fs->total_bytes); //printf("mpeg3bits_next_startcode 2 %llx\n", mpeg3bits_tell(stream)); /* Perform search */ while(1) { unsigned int code = mpeg3bits_showbits32_noptr(stream); if((code >> 8) == MPEG3_PACKET_START_CODE_PREFIX) break; if(mpeg3bits_eof(stream)) break; mpeg3bits_getbyte_noptr(stream); /* * printf("mpeg3bits_next_startcode 3 %08x %d %d\n", * mpeg3bits_showbits32_noptr(stream), * stream->demuxer->titles[0]->fs->current_byte, * stream->demuxer->titles[0]->fs->total_bytes); */ } //printf("mpeg3bits_next_startcode 4 %d %d\n", // stream->demuxer->titles[0]->fs->current_byte, // stream->demuxer->titles[0]->fs->total_bytes); return mpeg3bits_showbits32_noptr(stream); } /* Line up on the beginning of the next code. */ int mpeg3video_next_code(mpeg3_bits_t* stream, unsigned int code) { while(!mpeg3bits_eof(stream) && mpeg3bits_showbits32_noptr(stream) != code) { mpeg3bits_getbyte_noptr(stream); } return mpeg3bits_eof(stream); } /* Line up on the beginning of the previous code. */ int mpeg3video_prev_code(mpeg3_bits_t* stream, unsigned int code) { while(!mpeg3bits_bof(stream) && mpeg3bits_showbits_reverse(stream, 32) != code) { //printf("mpeg3video_prev_code %08x %08x\n", //mpeg3bits_showbits_reverse(stream, 32), mpeg3demux_tell(stream->demuxer)); mpeg3bits_getbits_reverse(stream, 8); } return mpeg3bits_bof(stream); } long mpeg3video_goptimecode_to_frame(mpeg3video_t *video) { /* printf("mpeg3video_goptimecode_to_frame %d %d %d %d %f\n", */ /* video->gop_timecode.hour, video->gop_timecode.minute, video->gop_timecode.second, video->gop_timecode.frame, video->frame_rate); */ return (long)(video->gop_timecode.hour * 3600 * video->frame_rate + video->gop_timecode.minute * 60 * video->frame_rate + video->gop_timecode.second * video->frame_rate + video->gop_timecode.frame) - 1 - video->first_frame; } int mpeg3video_match_refframes(mpeg3video_t *video) { unsigned char *dst, *src; int i, j, size; for(i = 0; i < 3; i++) { if(video->newframe[i]) { if(video->newframe[i] == video->refframe[i]) { src = video->refframe[i]; dst = video->oldrefframe[i]; } else { src = video->oldrefframe[i]; dst = video->refframe[i]; } if(i == 0) size = video->coded_picture_width * video->coded_picture_height + 32 * video->coded_picture_width; else size = video->chrom_width * video->chrom_height + 32 * video->chrom_width; memcpy(dst, src, size); } } return 0; } int mpeg3video_seek_byte(mpeg3video_t *video, int64_t byte) { mpeg3_t *file = video->file; mpeg3_bits_t *vstream = video->vstream; mpeg3_demuxer_t *demuxer = vstream->demuxer; video->byte_seek = byte; // Need PTS now so audio can be synchronized mpeg3bits_seek_byte(vstream, byte); // file->percentage_pts = mpeg3demux_scan_pts(demuxer); return 0; } int mpeg3video_seek_frame(mpeg3video_t *video, long frame) { video->frame_seek = frame; return 0; } int mpeg3video_seek(mpeg3video_t *video) { long this_gop_start; int result = 0; int back_step; int attempts; mpeg3_t *file = video->file; mpeg3_bits_t *vstream = video->vstream; mpeg3_vtrack_t *track = video->track; mpeg3_demuxer_t *demuxer = vstream->demuxer; int64_t byte; long frame_number; int match_refframes = 1; // Must do seeking here so files which don't use video don't seek. /* Seek to absolute byte */ if(video->byte_seek >= 0) { //printf("mpeg3video_seek 1\n"); byte = video->byte_seek; video->byte_seek = -1; mpeg3bits_seek_byte(vstream, byte); // Rewind 2 I-frames if(byte > 0) { mpeg3bits_start_reverse(vstream); if(video->has_gops) result = mpeg3video_prev_code(vstream, MPEG3_GOP_START_CODE); else result = mpeg3video_prev_code(vstream, MPEG3_SEQUENCE_START_CODE); if(!result) mpeg3bits_getbits_reverse(vstream, 32); if(video->has_gops) result = mpeg3video_prev_code(vstream, MPEG3_GOP_START_CODE); else result = mpeg3video_prev_code(vstream, MPEG3_SEQUENCE_START_CODE); if(!result) mpeg3bits_getbits_reverse(vstream, 32); mpeg3bits_start_forward(vstream); } // Reread first I frame // mpeg3video_get_firstframe(video); // mpeg3video_read_frame_backend(video, 0); // Read up to the correct byte result = 0; while(!result && mpeg3bits_tell(vstream) < byte) { result = mpeg3video_read_frame_backend(video, 0); } mpeg3demux_reset_pts(demuxer); //printf("mpeg3video_seek 10\n"); } else /* Seek to a frame */ if(video->frame_seek >= 0) { frame_number = video->frame_seek; video->frame_seek = -1; if(frame_number < 0) frame_number = 0; if(frame_number > video->maxframe) frame_number = video->maxframe; //printf("mpeg3video_seek 1 %ld %ld\n", frame_number, video->framenum); /* Seek to I frame in table of contents */ if(track->frame_offsets) { //printf("mpeg3video_seek 2 %d %d\n", video->framenum, frame_number); if((frame_number < video->framenum || frame_number - video->framenum > MPEG3_SEEK_THRESHOLD)) { int i; for(i = track->total_keyframe_numbers - 1; i >= 0; i--) { //printf("mpeg3video_seek 3 %lld %d\n", track->keyframe_numbers[i], frame_number); if(track->keyframe_numbers[i] <= frame_number) { int frame; int title_number; int64_t byte; // Go 2 I-frames before current position if(i > 0) i--; frame = track->keyframe_numbers[i]; title_number = (track->frame_offsets[frame] & 0xff00000000000000) >> 56; byte = track->frame_offsets[frame] & 0xffffffffffffff; video->framenum = track->keyframe_numbers[i]; mpeg3bits_open_title(vstream, title_number); mpeg3bits_seek_byte(vstream, byte); // Get first 2 I-frames if(byte == 0) { mpeg3video_get_firstframe(video); mpeg3video_read_frame_backend(video, 0); } //printf("mpeg3video_seek 2 %ld %ld\n", frame_number, video->framenum); mpeg3video_drop_frames(video, frame_number - video->framenum); break; } } } else { mpeg3video_drop_frames(video, frame_number - video->framenum); } } else /* Seek to start of file */ if(frame_number < 16) { video->repeat_count = video->current_repeat = 0; mpeg3bits_seek_start(vstream); video->framenum = 0; result = mpeg3video_drop_frames(video, frame_number - video->framenum); } else { /* Seek to an I frame. */ //printf(__FUNCTION__ " frame_number=%d video->framenum=%d\n", frame_number, video->framenum); if((frame_number < video->framenum || frame_number - video->framenum > MPEG3_SEEK_THRESHOLD)) { /* Elementary stream. Estimate frame position from total bytes. */ if(file->is_video_stream) { mpeg3_t *file = video->file; mpeg3_vtrack_t *track = video->track; int64_t byte = (int64_t)((double)(mpeg3demux_movie_size(demuxer) / track->total_frames) * frame_number); long minimum = 65535; int done = 0; /* Get GOP just before frame */ do { result = mpeg3bits_seek_byte(vstream, byte); mpeg3bits_start_reverse(vstream); if(!result) result = mpeg3video_prev_code(vstream, MPEG3_GOP_START_CODE); mpeg3bits_start_forward(vstream); mpeg3bits_getbits(vstream, 8); if(!result) result = mpeg3video_getgophdr(video); this_gop_start = mpeg3video_goptimecode_to_frame(video); //printf("wanted %ld guessed %ld byte %ld result %d\n", frame_number, this_gop_start, byte, result); if(labs(this_gop_start - frame_number) >= labs(minimum)) done = 1; else { minimum = this_gop_start - frame_number; byte += (long)((float)(frame_number - this_gop_start) * (double)(mpeg3demux_movie_size(demuxer) / track->total_frames)); if(byte < 0) byte = 0; } }while(!result && !done); //printf("wanted %d guessed %d\n", frame_number, this_gop_start); if(!result) { video->framenum = this_gop_start; result = mpeg3video_drop_frames(video, frame_number - video->framenum); } } else /* System stream */ { mpeg3bits_seek_time(vstream, (double)frame_number / video->frame_rate); byte = mpeg3bits_tell(vstream); mpeg3bits_start_reverse(vstream); mpeg3video_prev_code(vstream, MPEG3_GOP_START_CODE); mpeg3bits_getbits_reverse(vstream, 32); mpeg3bits_start_forward(vstream); while(!result && mpeg3bits_tell(vstream) < byte) { result = mpeg3video_read_frame_backend(video, 0); if(match_refframes) mpeg3video_match_refframes(video); match_refframes = 0; } //printf("seek system 3 %f\n", (double)frame_number / video->frame_rate); } video->framenum = frame_number; } else // Drop frames { mpeg3video_drop_frames(video, frame_number - video->framenum); } } mpeg3demux_reset_pts(demuxer); } return result; } int mpeg3video_previous_frame(mpeg3video_t *video) { if(mpeg3bits_tell(video->vstream) <= 0) return 1; // Get one picture mpeg3bits_start_reverse(video->vstream); mpeg3video_prev_code(video->vstream, MPEG3_PICTURE_START_CODE); mpeg3bits_getbits_reverse(video->vstream, 32); if(mpeg3bits_bof(video->vstream)) mpeg3bits_seek_byte(video->vstream, 0); mpeg3bits_start_forward(video->vstream); video->repeat_count = 0; return 0; } int mpeg3video_drop_frames(mpeg3video_t *video, long frames) { int result = 0; long frame_number = video->framenum + frames; //printf("mpeg3video_drop_frames 1 %d %d\n", frame_number, video->framenum); /* Read the selected number of frames and skip b-frames */ while(!result && frame_number > video->framenum) { result = mpeg3video_read_frame_backend(video, frame_number - video->framenum); } //printf("mpeg3video_drop_frames 100\n"); return result; } libmpeg3-1.5.4/video/Makefile0000644000175000017500000000053207742725646016230 0ustar enderender00000000000000include ../global_config export CFLAGS OBJS = \ getpicture.o \ headers.o \ idct.o \ macroblocks.o \ mmxtest.o \ motion.o \ mpeg3video.o \ output.o \ reconstruct.o \ seek.o \ slice.o \ vlc.o all: $(OBJS) $(MMXOBJS2) .c.o: $(CC) -c `./c_flags` $*.c .s.o: $(NASM) -f elf $*.s .S.o: $(CC) -c `./c_flags` $*.S clean: rm -f *.o libmpeg3-1.5.4/video/c_flags0000755000175000017500000000001507742725646016110 0ustar enderender00000000000000echo $CFLAGS libmpeg3-1.5.4/video/getpicture.c0000644000175000017500000004446207750130201017071 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include "vlc.h" #include #include #include int mpeg3video_get_cbp(mpeg3_slice_t *slice) { int code; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; if((code = mpeg3slice_showbits9(slice_buffer)) >= 128) { code >>= 4; mpeg3slice_flushbits(slice_buffer, mpeg3_CBPtab0[code].len); return mpeg3_CBPtab0[code].val; } if(code >= 8) { code >>= 1; mpeg3slice_flushbits(slice_buffer, mpeg3_CBPtab1[code].len); return mpeg3_CBPtab1[code].val; } if(code < 1) { /* fprintf(stderr,"mpeg3video_get_cbp: invalid coded_block_pattern code\n"); */ slice->fault = 1; return 0; } mpeg3slice_flushbits(slice_buffer, mpeg3_CBPtab2[code].len); return mpeg3_CBPtab2[code].val; } /* set block to zero */ int mpeg3video_clearblock(mpeg3_slice_t *slice, int comp, int size) { slice->sparse[comp] = 1; /* Compiler error with 2.95 required hard coding the size to 6 */ bzero(slice->block[comp], sizeof(short) * 64 * size); // memset(slice->block[comp], 0, sizeof(short) * 64 * size); return 0; } static inline int mpeg3video_getdclum(mpeg3_slice_buffer_t *slice_buffer) { int code, size, val; /* decode length */ code = mpeg3slice_showbits5(slice_buffer); if(code < 31) { size = mpeg3_DClumtab0[code].val; mpeg3slice_flushbits(slice_buffer, mpeg3_DClumtab0[code].len); } else { code = mpeg3slice_showbits9(slice_buffer) - 0x1f0; size = mpeg3_DClumtab1[code].val; mpeg3slice_flushbits(slice_buffer, mpeg3_DClumtab1[code].len); } if(size == 0) val = 0; else { val = mpeg3slice_getbits(slice_buffer, size); if((val & (1 << (size - 1))) == 0) val -= (1 << size) - 1; } return val; } int mpeg3video_getdcchrom(mpeg3_slice_buffer_t *slice_buffer) { int code, size, val; /* decode length */ code = mpeg3slice_showbits5(slice_buffer); if(code < 31) { size = mpeg3_DCchromtab0[code].val; mpeg3slice_flushbits(slice_buffer, mpeg3_DCchromtab0[code].len); } else { code = mpeg3slice_showbits(slice_buffer, 10) - 0x3e0; size = mpeg3_DCchromtab1[code].val; mpeg3slice_flushbits(slice_buffer, mpeg3_DCchromtab1[code].len); } if(size == 0) val = 0; else { val = mpeg3slice_getbits(slice_buffer, size); if((val & (1 << (size - 1))) == 0) val -= (1 << size) - 1; } return val; } /* decode one intra coded MPEG-1 block */ int mpeg3video_getintrablock(mpeg3_slice_t *slice, mpeg3video_t *video, int comp, int dc_dct_pred[]) { int val, i, j = 8, sign; unsigned int code; mpeg3_DCTtab_t *tab = 0; short *bp = slice->block[comp]; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; /* decode DC coefficients */ if(comp < 4) bp[0] = (dc_dct_pred[0] += mpeg3video_getdclum(slice_buffer)) << 3; else if(comp == 4) bp[0] = (dc_dct_pred[1] += mpeg3video_getdcchrom(slice_buffer)) << 3; else bp[0] = (dc_dct_pred[2] += mpeg3video_getdcchrom(slice_buffer)) << 3; #ifdef HAVE_MMX if(video->have_mmx) bp[0] <<= 4; #endif if(slice->fault) return 1; /* decode AC coefficients */ for(i = 1; ; i++) { code = mpeg3slice_showbits16(slice_buffer); if(code >= 16384) tab = &mpeg3_DCTtabnext[(code >> 12) - 4]; else if(code >= 1024) tab = &mpeg3_DCTtab0[(code >> 8) - 4]; else if(code >= 512) tab = &mpeg3_DCTtab1[(code >> 6) - 8]; else if(code >= 256) tab = &mpeg3_DCTtab2[(code >> 4) - 16]; else if(code >= 128) tab = &mpeg3_DCTtab3[(code >> 3) - 16]; else if(code >= 64) tab = &mpeg3_DCTtab4[(code >> 2) - 16]; else if(code >= 32) tab = &mpeg3_DCTtab5[(code >> 1) - 16]; else if(code >= 16) tab = &mpeg3_DCTtab6[code - 16]; else { /* fprintf(stderr, "mpeg3video_getintrablock: invalid Huffman code\n"); */ slice->fault = 1; return 0; } mpeg3slice_flushbits(slice_buffer, tab->len); if(tab->run == 64) break; /* end_of_block */ if(tab->run == 65) { /* escape */ i += mpeg3slice_getbits(slice_buffer, 6); if((val = mpeg3slice_getbits(slice_buffer, 8)) == 0) val = mpeg3slice_getbits(slice_buffer, 8); else if(val == 128) val = mpeg3slice_getbits(slice_buffer, 8) - 256; else if(val > 128) val -= 256; if((sign = (val < 0)) != 0) val= -val; } else { i += tab->run; val = tab->level; sign = mpeg3slice_getbit(slice_buffer); } if(i < 64) j = video->mpeg3_zigzag_scan_table[i]; else { slice->fault = 1; return 0; } #ifdef HAVE_MMX if(video->have_mmx) { val = (val * slice->quant_scale * video->intra_quantizer_matrix[j]) << 1; val = (val - 16) | 16; } else #endif { val = (val * slice->quant_scale * video->intra_quantizer_matrix[j]) >> 3; val = (val - 1) | 1; } bp[j] = sign ? -val : val; } if(j != 0) { /* not a sparse matrix ! */ slice->sparse[comp] = 0; } return 0; } /* decode one non-intra coded MPEG-1 block */ int mpeg3video_getinterblock(mpeg3_slice_t *slice, mpeg3video_t *video, int comp) { int val, i, j, sign; unsigned int code; mpeg3_DCTtab_t *tab; short *bp = slice->block[comp]; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; /* decode AC coefficients */ for(i = 0; ; i++) { code = mpeg3slice_showbits16(slice_buffer); if(code >= 16384) { if(i == 0) tab = &mpeg3_DCTtabfirst[(code >> 12) - 4]; else tab = &mpeg3_DCTtabnext[(code >> 12) - 4]; } else if(code >= 1024) tab = &mpeg3_DCTtab0[(code >> 8) - 4]; else if(code >= 512) tab = &mpeg3_DCTtab1[(code >> 6) - 8]; else if(code >= 256) tab = &mpeg3_DCTtab2[(code >> 4) - 16]; else if(code >= 128) tab = &mpeg3_DCTtab3[(code >> 3) - 16]; else if(code >= 64) tab = &mpeg3_DCTtab4[(code >> 2) - 16]; else if(code >= 32) tab = &mpeg3_DCTtab5[(code >> 1) - 16]; else if(code >= 16) tab = &mpeg3_DCTtab6[code - 16]; else { // invalid Huffman code slice->fault = 1; return 1; } mpeg3slice_flushbits(slice_buffer, tab->len); /* end of block */ if(tab->run == 64) break; if(tab->run == 65) { /* escape */ i += mpeg3slice_getbits(slice_buffer, 6); if((val = mpeg3slice_getbits(slice_buffer, 8)) == 0) val = mpeg3slice_getbits(slice_buffer, 8); else if(val == 128) val = mpeg3slice_getbits(slice_buffer, 8) - 256; else if(val > 128) val -= 256; if((sign = (val < 0)) != 0) val = -val; } else { i += tab->run; val = tab->level; sign = mpeg3slice_getbit(slice_buffer); } j = video->mpeg3_zigzag_scan_table[i]; #ifdef HAVE_MMX if(video->have_mmx) { val = (((val << 1)+1) * slice->quant_scale * video->non_intra_quantizer_matrix[j]); val = (val - 16) | 16; } else #endif { val = (((val << 1)+1) * slice->quant_scale * video->non_intra_quantizer_matrix[j]) >> 4; val = (val - 1) | 1; } bp[j] = sign ? -val : val; } if(j != 0) { /* not a sparse matrix ! */ slice->sparse[comp] = 0; } return 0; } /* decode one intra coded MPEG-2 block */ int mpeg3video_getmpg2intrablock(mpeg3_slice_t *slice, mpeg3video_t *video, int comp, int dc_dct_pred[]) { int val, i, j, sign, nc; unsigned int code; mpeg3_DCTtab_t *tab; short *bp; int *qmat; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; /* with data partitioning, data always goes to base layer */ bp = slice->block[comp]; qmat = (comp < 4 || video->chroma_format == CHROMA420) ? video->intra_quantizer_matrix : video->chroma_intra_quantizer_matrix; /* decode DC coefficients */ if(comp < 4) val = (dc_dct_pred[0] += mpeg3video_getdclum(slice_buffer)); else if((comp & 1) == 0) val = (dc_dct_pred[1] += mpeg3video_getdcchrom(slice_buffer)); else val = (dc_dct_pred[2] += mpeg3video_getdcchrom(slice_buffer)); if(slice->fault) return 0; #ifdef HAVE_MMX if(video->have_mmx) bp[0] = val << (7 - video->dc_prec); else #endif bp[0] = val << (3 - video->dc_prec); nc = 0; /* decode AC coefficients */ for(i = 1; ; i++) { code = mpeg3slice_showbits16(slice_buffer); if(code >= 16384 && !video->intravlc) tab = &mpeg3_DCTtabnext[(code >> 12) - 4]; else if(code >= 1024) { if(video->intravlc) tab = &mpeg3_DCTtab0a[(code >> 8) - 4]; else tab = &mpeg3_DCTtab0[(code >> 8) - 4]; } else if(code >= 512) { if(video->intravlc) tab = &mpeg3_DCTtab1a[(code >> 6) - 8]; else tab = &mpeg3_DCTtab1[(code >> 6) - 8]; } else if(code >= 256) tab = &mpeg3_DCTtab2[(code >> 4) - 16]; else if(code >= 128) tab = &mpeg3_DCTtab3[(code >> 3) - 16]; else if(code >= 64) tab = &mpeg3_DCTtab4[(code >> 2) - 16]; else if(code >= 32) tab = &mpeg3_DCTtab5[(code >> 1) - 16]; else if(code >= 16) tab = &mpeg3_DCTtab6[code - 16]; else { /* fprintf(stderr,"mpeg3video_getmpg2intrablock: invalid Huffman code\n"); */ slice->fault = 1; return 1; } mpeg3slice_flushbits(slice_buffer, tab->len); /* end_of_block */ if(tab->run == 64) break; if(tab->run == 65) { /* escape */ i += mpeg3slice_getbits(slice_buffer, 6); val = mpeg3slice_getbits(slice_buffer, 12); if((val & 2047) == 0) { // invalid signed_level (escape) slice->fault = 1; return 0; } if((sign = (val >= 2048)) != 0) val = 4096 - val; } else { i += tab->run; val = tab->level; sign = mpeg3slice_getbit(slice_buffer); } j = (video->altscan ? video->mpeg3_alternate_scan_table : video->mpeg3_zigzag_scan_table)[i]; #ifdef HAVE_MMX if(video->have_mmx) val = (val * slice->quant_scale * qmat[j]); else #endif val = (val * slice->quant_scale * qmat[j]) >> 4; bp[j] = sign ? -val : val; nc++; } if(j != 0) { /* not a sparse matrix ! */ slice->sparse[comp] = 0; } return 1; } /* decode one non-intra coded MPEG-2 block */ int mpeg3video_getmpg2interblock(mpeg3_slice_t *slice, mpeg3video_t *video, int comp) { int val, i, j, sign, nc; unsigned int code; mpeg3_DCTtab_t *tab; short *bp; int *qmat; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; /* with data partitioning, data always goes to base layer */ bp = slice->block[comp]; qmat = (comp < 4 || video->chroma_format == CHROMA420) ? video->non_intra_quantizer_matrix : video->chroma_non_intra_quantizer_matrix; nc = 0; /* decode AC coefficients */ for(i = 0; ; i++) { code = mpeg3slice_showbits16(slice_buffer); if(code >= 16384) { if(i == 0) tab = &mpeg3_DCTtabfirst[(code >> 12) - 4]; else tab = &mpeg3_DCTtabnext[(code >> 12) - 4]; } else if(code >= 1024) tab = &mpeg3_DCTtab0[(code >> 8) - 4]; else if(code >= 512) tab = &mpeg3_DCTtab1[(code >> 6) - 8]; else if(code >= 256) tab = &mpeg3_DCTtab2[(code >> 4) - 16]; else if(code >= 128) tab = &mpeg3_DCTtab3[(code >> 3) - 16]; else if(code >= 64) tab = &mpeg3_DCTtab4[(code >> 2) - 16]; else if(code >= 32) tab = &mpeg3_DCTtab5[(code >> 1) - 16]; else if(code >= 16) tab = &mpeg3_DCTtab6[code - 16]; else { // invalid Huffman code slice->fault = 1; return 0; } mpeg3slice_flushbits(slice_buffer, tab->len); /* end_of_block */ if(tab->run == 64) break; if(tab->run == 65) { /* escape */ i += mpeg3slice_getbits(slice_buffer, 6); val = mpeg3slice_getbits(slice_buffer, 12); if((val & 2047) == 0) { /* fprintf(stderr, "mpeg3video_getmpg2interblock: invalid signed_level (escape)\n"); */ slice->fault = 1; return 1; } if((sign = (val >= 2048)) != 0) val = 4096 - val; } else { i += tab->run; val = tab->level; sign = mpeg3slice_getbit(slice_buffer); } j = (video->altscan ? video->mpeg3_alternate_scan_table : video->mpeg3_zigzag_scan_table)[i]; #ifdef HAVE_MMX if(video->have_mmx) val = (((val << 1)+1) * slice->quant_scale * qmat[j]) >> 1; else #endif val = (((val << 1)+1) * slice->quant_scale * qmat[j]) >> 5; bp[j] = sign ? (-val) : val ; nc++; } if(j != 0) { slice->sparse[comp] = 0; } return 0; } /* decode all macroblocks of the current picture */ int mpeg3video_get_macroblocks(mpeg3video_t *video, int framenum) { unsigned int code; mpeg3_slice_buffer_t *slice_buffer; /* Buffer being loaded */ int i; int current_buffer; mpeg3_bits_t *vstream = video->vstream; /* Load every slice into a buffer array */ video->total_slice_buffers = 0; current_buffer = 0; while(!mpeg3bits_eof(vstream) && mpeg3bits_showbits32_noptr(vstream) >= MPEG3_SLICE_MIN_START && mpeg3bits_showbits32_noptr(vstream) <= MPEG3_SLICE_MAX_START && video->total_slice_buffers < MPEG3_MAX_CPUS) { /* Initialize the buffer */ if(current_buffer >= video->slice_buffers_initialized) mpeg3_new_slice_buffer(&(video->slice_buffers[video->slice_buffers_initialized++])); slice_buffer = &(video->slice_buffers[current_buffer]); slice_buffer->buffer_size = 0; slice_buffer->current_position = 0; slice_buffer->bits_size = 0; slice_buffer->done = 0; /* Read the slice into the buffer including the slice start code */ do { /* Expand buffer */ if(slice_buffer->buffer_allocation <= slice_buffer->buffer_size) mpeg3_expand_slice_buffer(slice_buffer); /* Load 1 char into buffer */ slice_buffer->data[slice_buffer->buffer_size++] = mpeg3bits_getbyte_noptr(vstream); }while(!mpeg3bits_eof(vstream) && mpeg3bits_showbits24_noptr(vstream) != MPEG3_PACKET_START_CODE_PREFIX); /* Pad the buffer to get the last macroblock */ if(slice_buffer->buffer_allocation <= slice_buffer->buffer_size + 4) mpeg3_expand_slice_buffer(slice_buffer); slice_buffer->data[slice_buffer->buffer_size++] = 0; slice_buffer->data[slice_buffer->buffer_size++] = 0; slice_buffer->data[slice_buffer->buffer_size++] = 1; slice_buffer->data[slice_buffer->buffer_size++] = 0; slice_buffer->bits_size = 0; pthread_mutex_lock(&(slice_buffer->completion_lock)); fflush(stdout); current_buffer++; video->total_slice_buffers++; } /* Run the slice decoders */ if(video->total_slice_buffers > 0) { for(i = 0; i < video->total_slice_decoders; i++) { if(i == 0 && video->total_slice_decoders > 1) { video->slice_decoders[i].current_buffer = 0; video->slice_decoders[i].buffer_step = 1; video->slice_decoders[i].last_buffer = (video->total_slice_buffers - 1); } else if(i == 1) { video->slice_decoders[i].current_buffer = video->total_slice_buffers - 1; video->slice_decoders[i].buffer_step = -1; video->slice_decoders[i].last_buffer = 0; } else { video->slice_decoders[i].current_buffer = i; video->slice_decoders[i].buffer_step = 1; video->slice_decoders[i].last_buffer = video->total_slice_buffers - 1; } pthread_mutex_unlock(&(video->slice_decoders[i].input_lock)); } } /* Wait for the slice buffers to finish */ if(video->total_slice_buffers > 0) { for(i = 0; i < video->total_slice_buffers; i++) { pthread_mutex_lock(&(video->slice_buffers[i].completion_lock)); pthread_mutex_unlock(&(video->slice_buffers[i].completion_lock)); } /* Wait for decoders to finish so packages aren't overwritten */ for(i = 0; i < video->total_slice_decoders; i++) { pthread_mutex_lock(&(video->slice_decoders[i].completion_lock)); } } return 0; } int mpeg3video_allocate_decoders(mpeg3video_t *video, int decoder_count) { int i; mpeg3_t *file = video->file; /* Get the slice decoders */ if(video->total_slice_decoders != file->cpus) { for(i = 0; i < video->total_slice_decoders; i++) { mpeg3_delete_slice_decoder(&(video->slice_decoders[i])); } for(i = 0; i < file->cpus && i < MPEG3_MAX_CPUS; i++) { mpeg3_new_slice_decoder(video, &(video->slice_decoders[i])); video->slice_decoders[i].thread_number = i; } video->total_slice_decoders = file->cpus; } return 0; } /* decode one frame or field picture */ int mpeg3video_getpicture(mpeg3video_t *video, int framenum) { int i, result = 0; mpeg3_t *file = video->file; if(video->pict_struct == FRAME_PICTURE && video->secondfield) { /* recover from illegal number of field pictures */ video->secondfield = 0; } if(!video->mpeg2) { video->current_repeat = video->repeat_count = 0; } mpeg3video_allocate_decoders(video, file->cpus); for(i = 0; i < 3; i++) { if(video->pict_type == B_TYPE) { video->newframe[i] = video->auxframe[i]; } else { if(!video->secondfield && !video->current_repeat) { /* Swap refframes for I frames */ unsigned char* tmp = video->oldrefframe[i]; video->oldrefframe[i] = video->refframe[i]; video->refframe[i] = tmp; } video->newframe[i] = video->refframe[i]; } if(video->pict_struct == BOTTOM_FIELD) { /* Only used if fields are in different pictures */ video->newframe[i] += (i == 0) ? video->coded_picture_width : video->chrom_width; } } /* The problem is when a B frame lands on the first repeat and is skipped, */ /* the second repeat goes for the same bitmap as the skipped repeat, */ /* so it picks up a frame from 3 frames back. */ /* The first repeat must consititutively read a B frame if its B frame is going to be */ /* used in a later repeat. */ if(!video->current_repeat) if(!(video->skip_bframes && video->pict_type == B_TYPE) || (video->repeat_count >= 100 + 100 * video->skip_bframes)) result = mpeg3video_get_macroblocks(video, framenum); /* Set the frame to display */ video->output_src = 0; if(framenum > -1 && !result) { if(video->pict_struct == FRAME_PICTURE || video->secondfield) { if(video->pict_type == B_TYPE) { video->output_src = video->auxframe; } else { video->output_src = video->oldrefframe; } } else { mpeg3video_display_second_field(video); } } if(video->mpeg2) { video->current_repeat += 100; } if(video->pict_struct != FRAME_PICTURE) video->secondfield = !video->secondfield; return result; } libmpeg3-1.5.4/video/headers.c0000644000175000017500000004044707742725646016360 0ustar enderender00000000000000#include "../mpeg3demux.h" #include "../mpeg3private.h" #include "../mpeg3protos.h" #include "mpeg3video.h" #include #include int mpeg3video_getseqhdr(mpeg3video_t *video) { int i; mpeg3_t *file = video->file; int aspect_ratio, picture_rate, vbv_buffer_size; int constrained_parameters_flag; int load_intra_quantizer_matrix, load_non_intra_quantizer_matrix; //printf("mpeg3video_getseqhdr 1\n"); video->horizontal_size = mpeg3bits_getbits(video->vstream, 12); video->vertical_size = mpeg3bits_getbits(video->vstream, 12); aspect_ratio = mpeg3bits_getbits(video->vstream, 4); video->framerate_code = mpeg3bits_getbits(video->vstream, 4); video->bitrate = mpeg3bits_getbits(video->vstream, 18); mpeg3bits_getbit_noptr(video->vstream); /* marker bit (=1) */ vbv_buffer_size = mpeg3bits_getbits(video->vstream, 10); constrained_parameters_flag = mpeg3bits_getbit_noptr(video->vstream); video->frame_rate = mpeg3_frame_rate_table[video->framerate_code]; load_intra_quantizer_matrix = mpeg3bits_getbit_noptr(video->vstream); if(load_intra_quantizer_matrix) { for(i = 0; i < 64; i++) video->intra_quantizer_matrix[video->mpeg3_zigzag_scan_table[i]] = mpeg3bits_getbyte_noptr(video->vstream); } else { for(i = 0; i < 64; i++) video->intra_quantizer_matrix[i] = mpeg3_default_intra_quantizer_matrix[i]; } load_non_intra_quantizer_matrix = mpeg3bits_getbit_noptr(video->vstream); if(load_non_intra_quantizer_matrix) { for(i = 0; i < 64; i++) video->non_intra_quantizer_matrix[video->mpeg3_zigzag_scan_table[i]] = mpeg3bits_getbyte_noptr(video->vstream); } else { for(i = 0; i < 64; i++) video->non_intra_quantizer_matrix[i] = 16; } /* copy luminance to chrominance matrices */ for(i = 0; i < 64; i++) { video->chroma_intra_quantizer_matrix[i] = video->intra_quantizer_matrix[i]; video->chroma_non_intra_quantizer_matrix[i] = video->non_intra_quantizer_matrix[i]; } //printf("mpeg3video_getseqhdr 100\n"); return 0; } /* decode sequence extension */ int mpeg3video_sequence_extension(mpeg3video_t *video) { int prof_lev; int horizontal_size_extension, vertical_size_extension; int bit_rate_extension, vbv_buffer_size_extension, low_delay; int frame_rate_extension_n, frame_rate_extension_d; int pos = 0; video->mpeg2 = 1; video->scalable_mode = SC_NONE; /* unless overwritten by seq. scal. ext. */ prof_lev = mpeg3bits_getbyte_noptr(video->vstream); video->prog_seq = mpeg3bits_getbit_noptr(video->vstream); video->chroma_format = mpeg3bits_getbits(video->vstream, 2); horizontal_size_extension = mpeg3bits_getbits(video->vstream, 2); vertical_size_extension = mpeg3bits_getbits(video->vstream, 2); bit_rate_extension = mpeg3bits_getbits(video->vstream, 12); mpeg3bits_getbit_noptr(video->vstream); vbv_buffer_size_extension = mpeg3bits_getbyte_noptr(video->vstream); low_delay = mpeg3bits_getbit_noptr(video->vstream); frame_rate_extension_n = mpeg3bits_getbits(video->vstream, 2); frame_rate_extension_d = mpeg3bits_getbits(video->vstream, 5); video->horizontal_size = (horizontal_size_extension << 12) | (video->horizontal_size & 0x0fff); video->vertical_size = (vertical_size_extension << 12) | (video->vertical_size & 0x0fff); return 0; } /* decode sequence display extension */ int mpeg3video_sequence_display_extension(mpeg3video_t *video) { int colour_primaries = 0, transfer_characteristics = 0; int display_horizontal_size, display_vertical_size; int pos = 0; int video_format = mpeg3bits_getbits(video->vstream, 3); int colour_description = mpeg3bits_getbit_noptr(video->vstream); if(colour_description) { colour_primaries = mpeg3bits_getbyte_noptr(video->vstream); transfer_characteristics = mpeg3bits_getbyte_noptr(video->vstream); video->matrix_coefficients = mpeg3bits_getbyte_noptr(video->vstream); } display_horizontal_size = mpeg3bits_getbits(video->vstream, 14); mpeg3bits_getbit_noptr(video->vstream); display_vertical_size = mpeg3bits_getbits(video->vstream, 14); return 0; } /* decode quant matrix entension */ int mpeg3video_quant_matrix_extension(mpeg3video_t *video) { int i; int load_intra_quantiser_matrix, load_non_intra_quantiser_matrix; int load_chroma_intra_quantiser_matrix; int load_chroma_non_intra_quantiser_matrix; int pos = 0; if((load_intra_quantiser_matrix = mpeg3bits_getbit_noptr(video->vstream)) != 0) { for(i = 0; i < 64; i++) { video->chroma_intra_quantizer_matrix[video->mpeg3_zigzag_scan_table[i]] = video->intra_quantizer_matrix[video->mpeg3_zigzag_scan_table[i]] = mpeg3bits_getbyte_noptr(video->vstream); } } if((load_non_intra_quantiser_matrix = mpeg3bits_getbit_noptr(video->vstream)) != 0) { for (i = 0; i < 64; i++) { video->chroma_non_intra_quantizer_matrix[video->mpeg3_zigzag_scan_table[i]] = video->non_intra_quantizer_matrix[video->mpeg3_zigzag_scan_table[i]] = mpeg3bits_getbyte_noptr(video->vstream); } } if((load_chroma_intra_quantiser_matrix = mpeg3bits_getbit_noptr(video->vstream)) != 0) { for(i = 0; i < 64; i++) video->chroma_intra_quantizer_matrix[video->mpeg3_zigzag_scan_table[i]] = mpeg3bits_getbyte_noptr(video->vstream); } if((load_chroma_non_intra_quantiser_matrix = mpeg3bits_getbit_noptr(video->vstream)) != 0) { for(i = 0; i < 64; i++) video->chroma_non_intra_quantizer_matrix[video->mpeg3_zigzag_scan_table[i]] = mpeg3bits_getbyte_noptr(video->vstream); } return 0; } /* decode sequence scalable extension */ int mpeg3video_sequence_scalable_extension(mpeg3video_t *video) { int layer_id; video->scalable_mode = mpeg3bits_getbits(video->vstream, 2) + 1; /* add 1 to make SC_DP != SC_NONE */ layer_id = mpeg3bits_getbits(video->vstream, 4); if(video->scalable_mode == SC_SPAT) { video->llw = mpeg3bits_getbits(video->vstream, 14); /* lower_layer_prediction_horizontal_size */ mpeg3bits_getbit_noptr(video->vstream); video->llh = mpeg3bits_getbits(video->vstream, 14); /* lower_layer_prediction_vertical_size */ video->hm = mpeg3bits_getbits(video->vstream, 5); video->hn = mpeg3bits_getbits(video->vstream, 5); video->vm = mpeg3bits_getbits(video->vstream, 5); video->vn = mpeg3bits_getbits(video->vstream, 5); } if(video->scalable_mode == SC_TEMP) fprintf(stderr, "mpeg3video_sequence_scalable_extension: temporal scalability not implemented\n"); return 0; } /* decode picture display extension */ int mpeg3video_picture_display_extension(mpeg3video_t *video) { int n, i; short frame_centre_horizontal_offset[3]; short frame_centre_vertical_offset[3]; if(video->prog_seq || video->pict_struct != FRAME_PICTURE) n = 1; else n = video->repeatfirst ? 3 : 2; for(i = 0; i < n; i++) { frame_centre_horizontal_offset[i] = (short)mpeg3bits_getbits(video->vstream, 16); mpeg3bits_getbit_noptr(video->vstream); frame_centre_vertical_offset[i] = (short)mpeg3bits_getbits(video->vstream, 16); mpeg3bits_getbit_noptr(video->vstream); } return 0; } /* decode picture coding extension */ int mpeg3video_picture_coding_extension(mpeg3video_t *video) { int chroma_420_type, composite_display_flag; int v_axis = 0, sub_carrier = 0, burst_amplitude = 0, sub_carrier_phase = 0; video->h_forw_r_size = mpeg3bits_getbits(video->vstream, 4) - 1; video->v_forw_r_size = mpeg3bits_getbits(video->vstream, 4) - 1; video->h_back_r_size = mpeg3bits_getbits(video->vstream, 4) - 1; video->v_back_r_size = mpeg3bits_getbits(video->vstream, 4) - 1; video->dc_prec = mpeg3bits_getbits(video->vstream, 2); video->pict_struct = mpeg3bits_getbits(video->vstream, 2); video->topfirst = mpeg3bits_getbit_noptr(video->vstream); video->frame_pred_dct = mpeg3bits_getbit_noptr(video->vstream); video->conceal_mv = mpeg3bits_getbit_noptr(video->vstream); video->qscale_type = mpeg3bits_getbit_noptr(video->vstream); video->intravlc = mpeg3bits_getbit_noptr(video->vstream); video->altscan = mpeg3bits_getbit_noptr(video->vstream); video->repeatfirst = mpeg3bits_getbit_noptr(video->vstream); chroma_420_type = mpeg3bits_getbit_noptr(video->vstream); video->prog_frame = mpeg3bits_getbit_noptr(video->vstream); if(video->repeat_count > 100) video->repeat_count = 0; video->repeat_count += 100; video->current_repeat = 0; if(video->prog_seq) { if(video->repeatfirst) { if(video->topfirst) video->repeat_count += 200; else video->repeat_count += 100; } } else if(video->prog_frame) { if(video->repeatfirst) { video->repeat_count += 50; } } //printf("mpeg3video_picture_coding_extension %d\n", video->repeat_count); composite_display_flag = mpeg3bits_getbit_noptr(video->vstream); if(composite_display_flag) { v_axis = mpeg3bits_getbit_noptr(video->vstream); video->field_sequence = mpeg3bits_getbits(video->vstream, 3); sub_carrier = mpeg3bits_getbit_noptr(video->vstream); burst_amplitude = mpeg3bits_getbits(video->vstream, 7); sub_carrier_phase = mpeg3bits_getbyte_noptr(video->vstream); } return 0; } /* decode picture spatial scalable extension */ int mpeg3video_picture_spatial_scalable_extension(mpeg3video_t *video) { video->pict_scal = 1; /* use spatial scalability in this picture */ video->lltempref = mpeg3bits_getbits(video->vstream, 10); mpeg3bits_getbit_noptr(video->vstream); video->llx0 = mpeg3bits_getbits(video->vstream, 15); if(video->llx0 >= 16384) video->llx0 -= 32768; mpeg3bits_getbit_noptr(video->vstream); video->lly0 = mpeg3bits_getbits(video->vstream, 15); if(video->lly0 >= 16384) video->lly0 -= 32768; video->stwc_table_index = mpeg3bits_getbits(video->vstream, 2); video->llprog_frame = mpeg3bits_getbit_noptr(video->vstream); video->llfieldsel = mpeg3bits_getbit_noptr(video->vstream); return 0; } /* decode picture temporal scalable extension * * not implemented * */ int mpeg3video_picture_temporal_scalable_extension(mpeg3video_t *video) { fprintf(stderr, "mpeg3video_picture_temporal_scalable_extension: temporal scalability not supported\n"); return 0; } /* decode extension and user data */ int mpeg3video_ext_user_data(mpeg3video_t *video) { int code = mpeg3bits_next_startcode(video->vstream); while((code == MPEG3_EXT_START_CODE || code == MPEG3_USER_START_CODE) && !mpeg3bits_eof(video->vstream)) { mpeg3bits_refill(video->vstream); if(code == MPEG3_EXT_START_CODE) { int ext_id = mpeg3bits_getbits(video->vstream, 4); switch(ext_id) { case SEQ_ID: mpeg3video_sequence_extension(video); break; case DISP_ID: mpeg3video_sequence_display_extension(video); break; case QUANT_ID: mpeg3video_quant_matrix_extension(video); break; case SEQSCAL_ID: mpeg3video_sequence_scalable_extension(video); break; case PANSCAN_ID: mpeg3video_picture_display_extension(video); break; case CODING_ID: mpeg3video_picture_coding_extension(video); break; case SPATSCAL_ID: mpeg3video_picture_spatial_scalable_extension(video); break; case TEMPSCAL_ID: mpeg3video_picture_temporal_scalable_extension(video); break; default: fprintf(stderr,"mpeg3video_ext_user_data: reserved extension start code ID %d\n", ext_id); break; } } code = mpeg3bits_next_startcode(video->vstream); } return 0; } /* decode group of pictures header */ int mpeg3video_getgophdr(mpeg3video_t *video) { int drop_flag, closed_gop, broken_link; //printf("mpeg3video_getgophdr 1\n"); video->has_gops = 1; drop_flag = mpeg3bits_getbit_noptr(video->vstream); video->gop_timecode.hour = mpeg3bits_getbits(video->vstream, 5); video->gop_timecode.minute = mpeg3bits_getbits(video->vstream, 6); mpeg3bits_getbit_noptr(video->vstream); video->gop_timecode.second = mpeg3bits_getbits(video->vstream, 6); video->gop_timecode.frame = mpeg3bits_getbits(video->vstream, 6); closed_gop = mpeg3bits_getbit_noptr(video->vstream); broken_link = mpeg3bits_getbit_noptr(video->vstream); //printf("mpeg3video_getgophdr 100\n"); /* * printf("%d:%d:%d:%d %d %d %d\n", video->gop_timecode.hour, video->gop_timecode.minute, video->gop_timecode.second, video->gop_timecode.frame, * drop_flag, closed_gop, broken_link); */ return mpeg3bits_error(video->vstream); } /* decode picture header */ int mpeg3video_getpicturehdr(mpeg3video_t *video) { int temp_ref, vbv_delay; video->pict_scal = 0; /* unless overwritten by pict. spat. scal. ext. */ temp_ref = mpeg3bits_getbits(video->vstream, 10); video->pict_type = mpeg3bits_getbits(video->vstream, 3); vbv_delay = mpeg3bits_getbits(video->vstream, 16); if(video->pict_type == P_TYPE || video->pict_type == B_TYPE) { video->full_forw = mpeg3bits_getbit_noptr(video->vstream); video->forw_r_size = mpeg3bits_getbits(video->vstream, 3) - 1; } if(video->pict_type == B_TYPE) { video->full_back = mpeg3bits_getbit_noptr(video->vstream); video->back_r_size = mpeg3bits_getbits(video->vstream, 3) - 1; } /* get extra bit picture */ while(mpeg3bits_getbit_noptr(video->vstream) && !mpeg3bits_eof(video->vstream)) mpeg3bits_getbyte_noptr(video->vstream); return 0; } int mpeg3video_get_header(mpeg3video_t *video, int dont_repeat) { unsigned int code; /* a sequence header should be found before returning from `getheader' the */ /* first time (this is to set horizontal/vertical size properly) */ /* Repeat the frame until it's less than 1 count from repeat_count */ if(video->repeat_count - video->current_repeat >= 100 && !dont_repeat) { return 0; } if(dont_repeat) { video->repeat_count = 0; video->current_repeat = 0; } else video->repeat_count -= video->current_repeat; // Case of no picture coding extension if(video->repeat_count < 0) video->repeat_count = 0; /* * printf("mpeg3video_get_header 2 %lld %lld\n", * video->vstream->demuxer->titles[0]->fs->current_byte, * video->vstream->demuxer->titles[0]->fs->total_bytes); */ while(1) { //printf("mpeg3video_get_header 10 %llx\n", mpeg3bits_tell(video->vstream)); /* look for startcode */ code = mpeg3bits_next_startcode(video->vstream); //printf("mpeg3video_get_header 20 %08x\n", code); /* * printf("mpeg3video_get_header 2 %llx %llx %08x\n", * video->vstream->demuxer->titles[0]->fs->current_byte, * video->vstream->demuxer->titles[0]->fs->total_bytes, * code); */ //printf("mpeg3video_get_header 2 %p\n", video->vstream->demuxer); if(mpeg3bits_eof(video->vstream)) return 1; //printf("mpeg3video_get_header 1\n"); if(code != MPEG3_SEQUENCE_END_CODE) mpeg3bits_refill(video->vstream); //printf("mpeg3video_get_header 1\n"); switch(code) { case MPEG3_SEQUENCE_START_CODE: video->found_seqhdr = 1; //printf("mpeg3video_get_header 1\n"); mpeg3video_getseqhdr(video); //printf("mpeg3video_get_header 1\n"); mpeg3video_ext_user_data(video); //printf("mpeg3video_get_header 100\n"); break; case MPEG3_GOP_START_CODE: mpeg3video_getgophdr(video); mpeg3video_ext_user_data(video); break; case MPEG3_PICTURE_START_CODE: //printf("%x\n", mpeg3bits_tell(video->vstream)); mpeg3video_getpicturehdr(video); mpeg3video_ext_user_data(video); if(video->found_seqhdr) return 0; /* Exit here */ break; case MPEG3_SEQUENCE_END_CODE: // Continue until the end mpeg3bits_refill(video->vstream); break; default: break; } } return 1; /* Shouldn't be reached. */ } int mpeg3video_ext_bit_info(mpeg3_slice_buffer_t *slice_buffer) { while(mpeg3slice_getbit(slice_buffer)) mpeg3slice_getbyte(slice_buffer); return 0; } /* decode slice header */ int mpeg3video_getslicehdr(mpeg3_slice_t *slice, mpeg3video_t *video) { int slice_vertical_position_extension, intra_slice; int qs; slice_vertical_position_extension = (video->mpeg2 && video->vertical_size > 2800) ? mpeg3slice_getbits(slice->slice_buffer, 3) : 0; if(video->scalable_mode == SC_DP) slice->pri_brk = mpeg3slice_getbits(slice->slice_buffer, 7); qs = mpeg3slice_getbits(slice->slice_buffer, 5); slice->quant_scale = video->mpeg2 ? (video->qscale_type ? mpeg3_non_linear_mquant_table[qs] : (qs << 1)) : qs; if(mpeg3slice_getbit(slice->slice_buffer)) { intra_slice = mpeg3slice_getbit(slice->slice_buffer); mpeg3slice_getbits(slice->slice_buffer, 7); mpeg3video_ext_bit_info(slice->slice_buffer); } else intra_slice = 0; return slice_vertical_position_extension; } libmpeg3-1.5.4/video/idct.c0000644000175000017500000000771707742725646015673 0ustar enderender00000000000000#include "idct.h" #include /**********************************************************/ /* inverse two dimensional DCT, Chen-Wang algorithm */ /* (cf. IEEE ASSP-32, pp. 803-816, Aug. 1984) */ /* 32-bit integer arithmetic (8 bit coefficients) */ /* 11 mults, 29 adds per DCT */ /* sE, 18.8.91 */ /**********************************************************/ /* coefficients extended to 12 bit for IEEE1180-1990 */ /* compliance sE, 2.1.94 */ /**********************************************************/ /* this code assumes >> to be a two's-complement arithmetic */ /* right shift: (-2)>>1 == -1 , (-3)>>1 == -2 */ #define W1 2841 /* 2048*sqrt(2)*cos(1*pi/16) */ #define W2 2676 /* 2048*sqrt(2)*cos(2*pi/16) */ #define W3 2408 /* 2048*sqrt(2)*cos(3*pi/16) */ #define W5 1609 /* 2048*sqrt(2)*cos(5*pi/16) */ #define W6 1108 /* 2048*sqrt(2)*cos(6*pi/16) */ #define W7 565 /* 2048*sqrt(2)*cos(7*pi/16) */ /* row (horizontal) IDCT * * 7 pi 1 * dst[k] = sum c[l] * src[l] * cos( -- * ( k + - ) * l ) * l=0 8 2 * * where: c[0] = 128 * c[1..7] = 128*sqrt(2) */ int mpeg3video_idctrow(short *blk) { int x0, x1, x2, x3, x4, x5, x6, x7, x8; /* shortcut */ if (!((x1 = blk[4]<<11) | (x2 = blk[6]) | (x3 = blk[2]) | (x4 = blk[1]) | (x5 = blk[7]) | (x6 = blk[5]) | (x7 = blk[3]))) { blk[0]=blk[1]=blk[2]=blk[3]=blk[4]=blk[5]=blk[6]=blk[7]=blk[0]<<3; return 0; } x0 = (blk[0]<<11) + 128; /* for proper rounding in the fourth stage */ /* first stage */ x8 = W7*(x4+x5); x4 = x8 + (W1-W7)*x4; x5 = x8 - (W1+W7)*x5; x8 = W3*(x6+x7); x6 = x8 - (W3-W5)*x6; x7 = x8 - (W3+W5)*x7; /* second stage */ x8 = x0 + x1; x0 -= x1; x1 = W6*(x3+x2); x2 = x1 - (W2+W6)*x2; x3 = x1 + (W2-W6)*x3; x1 = x4 + x6; x4 -= x6; x6 = x5 + x7; x5 -= x7; /* third stage */ x7 = x8 + x3; x8 -= x3; x3 = x0 + x2; x0 -= x2; x2 = (181*(x4+x5)+128)>>8; x4 = (181*(x4-x5)+128)>>8; /* fourth stage */ blk[0] = (x7+x1)>>8; blk[1] = (x3+x2)>>8; blk[2] = (x0+x4)>>8; blk[3] = (x8+x6)>>8; blk[4] = (x8-x6)>>8; blk[5] = (x0-x4)>>8; blk[6] = (x3-x2)>>8; blk[7] = (x7-x1)>>8; return 0; } /* column (vertical) IDCT * * 7 pi 1 * dst[8*k] = sum c[l] * src[8*l] * cos( -- * ( k + - ) * l ) * l=0 8 2 * * where: c[0] = 1/1024 * c[1..7] = (1/1024)*sqrt(2) */ int mpeg3video_idctcol(short *blk) { int x0, x1, x2, x3, x4, x5, x6, x7, x8; /* shortcut */ if (!((x1 = (blk[8 * 4]<<8)) | (x2 = blk[8 * 6]) | (x3 = blk[8 * 2]) | (x4 = blk[8*1]) | (x5 = blk[8 * 7]) | (x6 = blk[8 * 5]) | (x7 = blk[8 * 3]))){ blk[8*0]=blk[8*1]=blk[8 * 2]=blk[8 * 3]=blk[8 * 4]=blk[8 * 5]=blk[8 * 6]=blk[8 * 7]= (blk[8*0]+32)>>6; return 0; } x0 = (blk[8*0]<<8) + 8192; /* first stage */ x8 = W7*(x4+x5) + 4; x4 = (x8+(W1-W7)*x4)>>3; x5 = (x8-(W1+W7)*x5)>>3; x8 = W3*(x6+x7) + 4; x6 = (x8-(W3-W5)*x6)>>3; x7 = (x8-(W3+W5)*x7)>>3; /* second stage */ x8 = x0 + x1; x0 -= x1; x1 = W6*(x3+x2) + 4; x2 = (x1-(W2+W6)*x2)>>3; x3 = (x1+(W2-W6)*x3)>>3; x1 = x4 + x6; x4 -= x6; x6 = x5 + x7; x5 -= x7; /* third stage */ x7 = x8 + x3; x8 -= x3; x3 = x0 + x2; x0 -= x2; x2 = (181 * (x4 + x5) + 128) >> 8; x4 = (181 * (x4 - x5) + 128) >> 8; /* fourth stage */ blk[8 * 0] = (x7 + x1) >> 14; blk[8 * 1] = (x3 + x2) >> 14; blk[8 * 2] = (x0 + x4) >> 14; blk[8 * 3] = (x8 + x6) >> 14; blk[8 * 4] = (x8 - x6) >> 14; blk[8 * 5] = (x0 - x4) >> 14; blk[8 * 6] = (x3 - x2) >> 14; blk[8 * 7] = (x7 - x1) >> 14; return 0; } /* two dimensional inverse discrete cosine transform */ void mpeg3video_idct_conversion(short* block) { int i; for(i = 0; i < 8; i++) mpeg3video_idctrow(block + 8 * i); for(i = 0; i < 8; i++) mpeg3video_idctcol(block + i); } libmpeg3-1.5.4/video/idct.h0000644000175000017500000000004707742725646015665 0ustar enderender00000000000000#ifndef IDCT_H #define IDCT_H #endif libmpeg3-1.5.4/video/layerdata.h0000644000175000017500000000072307742725646016711 0ustar enderender00000000000000#ifndef LAYERDATA_H #define LAYERDATA_H typedef struct { /* sequence header */ int intra_quantizer_matrix[64], non_intra_quantizer_matrix[64]; int chroma_intra_quantizer_matrix[64], chroma_non_intra_quantizer_matrix[64]; int mpeg2; int qscale_type, altscan; /* picture coding extension */ int pict_scal; /* picture spatial scalable extension */ int scalable_mode; /* sequence scalable extension */ } mpeg3_layerdata_t; #endif libmpeg3-1.5.4/video/macroblocks.c0000644000175000017500000002032207742725646017232 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include "vlc.h" #include int mpeg3video_get_macroblock_address(mpeg3_slice_t *slice) { int code, val = 0; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; while((code = mpeg3slice_showbits(slice_buffer, 11)) < 24) { /* Is not macroblock_stuffing */ if(code != 15) { /* Is macroblock_escape */ if(code == 8) { val += 33; } else { /* fprintf(stderr, "mpeg3video_get_macroblock_address: invalid macroblock_address_increment code\n"); */ slice->fault = 1; return 1; } } mpeg3slice_flushbits(slice_buffer, 11); } if(code >= 1024) { mpeg3slice_flushbit(slice_buffer); return val + 1; } if(code >= 128) { code >>= 6; mpeg3slice_flushbits(slice_buffer, mpeg3_MBAtab1[code].len); return val + mpeg3_MBAtab1[code].val; } code -= 24; mpeg3slice_flushbits(slice_buffer, mpeg3_MBAtab2[code].len); return val + mpeg3_MBAtab2[code].val; } /* macroblock_type for pictures with spatial scalability */ static inline int mpeg3video_getsp_imb_type(mpeg3_slice_t *slice) { mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; unsigned int code = mpeg3slice_showbits(slice_buffer, 4); if(!code) { /* fprintf(stderr,"mpeg3video_getsp_imb_type: invalid macroblock_type code\n"); */ slice->fault = 1; return 0; } mpeg3slice_flushbits(slice_buffer, mpeg3_spIMBtab[code].len); return mpeg3_spIMBtab[code].val; } static inline int mpeg3video_getsp_pmb_type(mpeg3_slice_t *slice) { mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; int code = mpeg3slice_showbits(slice_buffer, 7); if(code < 2) { /* fprintf(stderr,"mpeg3video_getsp_pmb_type: invalid macroblock_type code\n"); */ slice->fault = 1; return 0; } if(code >= 16) { code >>= 3; mpeg3slice_flushbits(slice_buffer, mpeg3_spPMBtab0[code].len); return mpeg3_spPMBtab0[code].val; } mpeg3slice_flushbits(slice_buffer, mpeg3_spPMBtab1[code].len); return mpeg3_spPMBtab1[code].val; } static inline int mpeg3video_getsp_bmb_type(mpeg3_slice_t *slice) { mpeg3_VLCtab_t *p; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; int code = mpeg3slice_showbits9(slice_buffer); if(code >= 64) p = &mpeg3_spBMBtab0[(code >> 5) - 2]; else if(code >= 16) p = &mpeg3_spBMBtab1[(code >> 2) - 4]; else if(code >= 8) p = &mpeg3_spBMBtab2[code - 8]; else { /* fprintf(stderr,"mpeg3video_getsp_bmb_type: invalid macroblock_type code\n"); */ slice->fault = 1; return 0; } mpeg3slice_flushbits(slice_buffer, p->len); return p->val; } static inline int mpeg3video_get_imb_type(mpeg3_slice_t *slice) { mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; if(mpeg3slice_getbit(slice_buffer)) { return 1; } if(!mpeg3slice_getbit(slice_buffer)) { /* fprintf(stderr,"mpeg3video_get_imb_type: invalid macroblock_type code\n"); */ slice->fault = 1; } return 17; } static inline int mpeg3video_get_pmb_type(mpeg3_slice_t *slice) { int code; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; if((code = mpeg3slice_showbits(slice_buffer, 6)) >= 8) { code >>= 3; mpeg3slice_flushbits(slice_buffer, mpeg3_PMBtab0[code].len); return mpeg3_PMBtab0[code].val; } if(code == 0) { /* fprintf(stderr,"mpeg3video_get_pmb_type: invalid macroblock_type code\n"); */ slice->fault = 1; return 0; } mpeg3slice_flushbits(slice_buffer, mpeg3_PMBtab1[code].len); return mpeg3_PMBtab1[code].val; } static inline int mpeg3video_get_bmb_type(mpeg3_slice_t *slice) { int code; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; if((code = mpeg3slice_showbits(slice_buffer, 6)) >= 8) { code >>= 2; mpeg3slice_flushbits(slice_buffer, mpeg3_BMBtab0[code].len); return mpeg3_BMBtab0[code].val; } if(code == 0) { /* fprintf(stderr,"mpeg3video_get_bmb_type: invalid macroblock_type code\n"); */ slice->fault = 1; return 0; } mpeg3slice_flushbits(slice_buffer, mpeg3_BMBtab1[code].len); return mpeg3_BMBtab1[code].val; } static inline int mpeg3video_get_dmb_type(mpeg3_slice_t *slice) { if(!mpeg3slice_getbit(slice->slice_buffer)) { /* fprintf(stderr,"mpeg3video_get_dmb_type: invalid macroblock_type code\n"); */ slice->fault=1; } return 1; } static inline int mpeg3video_get_snrmb_type(mpeg3_slice_t *slice) { mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; int code = mpeg3slice_showbits(slice_buffer, 3); if(code == 0) { /* fprintf(stderr,"mpeg3video_get_snrmb_type: invalid macroblock_type code\n"); */ slice->fault = 1; return 0; } mpeg3slice_flushbits(slice_buffer, mpeg3_SNRMBtab[code].len); return mpeg3_SNRMBtab[code].val; } int mpeg3video_get_mb_type(mpeg3_slice_t *slice, mpeg3video_t *video) { if(video->scalable_mode == SC_SNR) { return mpeg3video_get_snrmb_type(slice); } else { switch(video->pict_type) { case I_TYPE: return video->pict_scal ? mpeg3video_getsp_imb_type(slice) : mpeg3video_get_imb_type(slice); case P_TYPE: return video->pict_scal ? mpeg3video_getsp_pmb_type(slice) : mpeg3video_get_pmb_type(slice); case B_TYPE: return video->pict_scal ? mpeg3video_getsp_bmb_type(slice) : mpeg3video_get_bmb_type(slice); case D_TYPE: return mpeg3video_get_dmb_type(slice); default: /*fprintf(stderr, "mpeg3video_getmbtype: unknown coding type\n"); */ break; /* MPEG-1 only, not implemented */ } } return 0; } int mpeg3video_macroblock_modes(mpeg3_slice_t *slice, mpeg3video_t *video, int *pmb_type, int *pstwtype, int *pstwclass, int *pmotion_type, int *pmv_count, int *pmv_format, int *pdmv, int *pmvscale, int *pdct_type) { int mb_type; int stwtype, stwcode, stwclass; int motion_type = 0, mv_count, mv_format, dmv, mvscale; int dct_type; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; static unsigned char stwc_table[3][4] = { {6,3,7,4}, {2,1,5,4}, {2,5,7,4} }; static unsigned char stwclass_table[9] = {0, 1, 2, 1, 1, 2, 3, 3, 4}; /* get macroblock_type */ mb_type = mpeg3video_get_mb_type(slice, video); if(slice->fault) return 1; /* get spatial_temporal_weight_code */ if(mb_type & MB_WEIGHT) { if(video->stwc_table_index == 0) stwtype = 4; else { stwcode = mpeg3slice_getbits2(slice_buffer); stwtype = stwc_table[video->stwc_table_index - 1][stwcode]; } } else stwtype = (mb_type & MB_CLASS4) ? 8 : 0; /* derive spatial_temporal_weight_class (Table 7-18) */ stwclass = stwclass_table[stwtype]; /* get frame/field motion type */ if(mb_type & (MB_FORWARD | MB_BACKWARD)) { if(video->pict_struct == FRAME_PICTURE) { /* frame_motion_type */ motion_type = video->frame_pred_dct ? MC_FRAME : mpeg3slice_getbits2(slice_buffer); } else { /* field_motion_type */ motion_type = mpeg3slice_getbits2(slice_buffer); } } else if((mb_type & MB_INTRA) && video->conceal_mv) { /* concealment motion vectors */ motion_type = (video->pict_struct == FRAME_PICTURE) ? MC_FRAME : MC_FIELD; } /* derive mv_count, mv_format and dmv, (table 6-17, 6-18) */ if(video->pict_struct == FRAME_PICTURE) { mv_count = (motion_type == MC_FIELD && stwclass < 2) ? 2 : 1; mv_format = (motion_type == MC_FRAME) ? MV_FRAME : MV_FIELD; } else { mv_count = (motion_type == MC_16X8) ? 2 : 1; mv_format = MV_FIELD; } dmv = (motion_type == MC_DMV); /* dual prime */ /* field mv predictions in frame pictures have to be scaled */ mvscale = ((mv_format == MV_FIELD) && (video->pict_struct == FRAME_PICTURE)); /* get dct_type (frame DCT / field DCT) */ dct_type = (video->pict_struct == FRAME_PICTURE) && (!video->frame_pred_dct) && (mb_type & (MB_PATTERN | MB_INTRA)) ? mpeg3slice_getbit(slice_buffer) : 0; /* return values */ *pmb_type = mb_type; *pstwtype = stwtype; *pstwclass = stwclass; *pmotion_type = motion_type; *pmv_count = mv_count; *pmv_format = mv_format; *pdmv = dmv; *pmvscale = mvscale; *pdct_type = dct_type; return 0; } libmpeg3-1.5.4/video/mmxidct.S0000644000175000017500000005076607742725646016377 0ustar enderender00000000000000/* * the input data is tranposed and each 16 bit element in the 8x8 matrix * is left aligned: * for example in 11...1110000 format * If the iDCT is of I macroblock then 0.5 needs to be added to the;DC Component * (element[0][0] of the matrix) */ /* extrn re_matrix */ /* constants */ .data .align 16 .type preSC, @object preSC: .short 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520 .short 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270 .short 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906 .short 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315 .short 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520 .short 12873, 17855, 16819, 15137, 25746, 20228, 13933, 7103 .short 17734, 24598, 23170, 20853, 17734, 13933, 9597, 4892 .short 18081, 25080, 23624, 21261, 18081, 14206, 9785, 4988 .size preSC, 128 .align 8 .type x0005000200010001, @object .size x0005000200010001, 8 x0005000200010001: .long 0x00010001, 0x00050002 .align 8 .type x0040000000000000, @object .size x0040000000000000, 8 x0040000000000000: .long 0, 0x00400000 .align 8 .type x5a825a825a825a82, @object .size x5a825a825a825a82, 8 x5a825a825a825a82: .long 0x5a825a82, 0x5a825a82 .align 8 .type x539f539f539f539f, @object .size x539f539f539f539f, 8 x539f539f539f539f: .long 0x539f539f, 0x539f539f .align 8 .type x4546454645464546, @object .size x4546454645464546, 8 x4546454645464546: .long 0x45464546, 0x45464546 .align 8 .type x61f861f861f861f8, @object .size x61f861f861f861f8, 8 x61f861f861f861f8: .long 0x61f861f8, 0x61f861f8 /* Static variables */ .align 8 .type x0, @object .size x0, 8 x0: .long 0, 0 /* Procedure */ .align 8 .text .align 4 .globl IDCT_mmx .type IDCT_mmx, @function IDCT_mmx: pushl %ebp movl %esp, %ebp pushl %ebx pushl %ecx pushl %edx pushl %esi pushl %edi pushl $0 /* allocate the temp variables */ pushl $0 pushl $0 pushl $0 pushl $0 pushl $0 pushl $0 pushl $0 movl 8(%ebp), %esi /* source matrix */ leal preSC, %ecx /* column 0: even part * use V4, V12, V0, V8 to produce V22..V25 */ movq 8*12(%ecx), %mm0 /* maybe the first mul can be done together */ /* with the dequantization in iHuff module */ pmulhw 8*12(%esi), %mm0 /* V12 */ movq 8*4(%ecx), %mm1 pmulhw 8*4(%esi), %mm1 /* V4 */ movq (%ecx), %mm3 psraw $1, %mm0 /* t64=t66 */ pmulhw (%esi), %mm3 /* V0 */ movq 8*8(%ecx), %mm5 /* duplicate V4 */ movq %mm1, %mm2 /* added 11/1/96 */ pmulhw 8*8(%esi),%mm5 /* V8 */ psubsw %mm0, %mm1 /* V16 */ pmulhw x5a825a825a825a82, %mm1 /* 23170 ->V18 */ paddsw %mm0, %mm2 /* V17 */ movq %mm2, %mm0 /* duplicate V17 */ psraw $1, %mm2 /* t75=t82 */ psraw $2, %mm0 /* t72 */ movq %mm3, %mm4 /* duplicate V0 */ paddsw %mm5, %mm3 /* V19 */ psubsw %mm5, %mm4 /* V20 ;mm5 free */ /* moved from the block below */ movq 8*10(%ecx), %mm7 psraw $1, %mm3 /* t74=t81 */ movq %mm3, %mm6 /* duplicate t74=t81 */ psraw $2, %mm4 /* t77=t79 */ psubsw %mm0, %mm1 /* V21 ; mm0 free */ paddsw %mm2, %mm3 /* V22 */ movq %mm1, %mm5 /* duplicate V21 */ paddsw %mm4, %mm1 /* V23 */ movq %mm3, 8*4(%esi) /* V22 */ psubsw %mm5, %mm4 /* V24; mm5 free */ movq %mm1, 8*12(%esi) /* V23 */ psubsw %mm2, %mm6 /* V25; mm2 free */ movq %mm4, (%esi) /* V24 */ /* keep mm6 alive all along the next block */ /* movq %mm6, 8*8(%esi) V25 */ /* column 0: odd part * use V2, V6, V10, V14 to produce V31, V39, V40, V41 */ /* moved above: movq 8*10(%ecx), %mm7 */ pmulhw 8*10(%esi), %mm7 /* V10 */ movq 8*6(%ecx), %mm0 pmulhw 8*6(%esi), %mm0 /* V6 */ movq 8*2(%ecx), %mm5 movq %mm7, %mm3 /* duplicate V10 */ pmulhw 8*2(%esi), %mm5 /* V2 */ movq 8*14(%ecx), %mm4 psubsw %mm0, %mm7 /* V26 */ pmulhw 8*14(%esi), %mm4 /* V14 */ paddsw %mm0, %mm3 /* V29 ; free mm0 */ movq %mm7, %mm1 /* duplicate V26 */ psraw $1, %mm3 /* t91=t94 */ pmulhw x539f539f539f539f,%mm7 /* V33 */ psraw $1, %mm1 /* t96 */ movq %mm5, %mm0 /* duplicate V2 */ psraw $2, %mm4 /* t85=t87 */ paddsw %mm4,%mm5 /* V27 */ psubsw %mm4, %mm0 /* V28 ; free mm4 */ movq %mm0, %mm2 /* duplicate V28 */ psraw $1, %mm5 /* t90=t93 */ pmulhw x4546454645464546,%mm0 /* V35 */ psraw $1, %mm2 /* t97 */ movq %mm5, %mm4 /* duplicate t90=t93 */ psubsw %mm2, %mm1 /* V32 ; free mm2 */ pmulhw x61f861f861f861f8,%mm1 /* V36 */ psllw $1, %mm7 /* t107 */ paddsw %mm3, %mm5 /* V31 */ psubsw %mm3, %mm4 /* V30 ; free mm3 */ pmulhw x5a825a825a825a82,%mm4 /* V34 */ nop psubsw %mm1, %mm0 /* V38 */ psubsw %mm7, %mm1 /* V37 ; free mm7 */ psllw $1, %mm1 /* t114 */ /* move from the next block */ movq %mm6, %mm3 /* duplicate V25 */ /* move from the next block */ movq 8*4(%esi), %mm7 /* V22 */ psllw $1, %mm0 /* t110 */ psubsw %mm5, %mm0 /* V39 (mm5 needed for next block) */ psllw $2, %mm4 /* t112 */ /* moved from the next block */ movq 8*12(%esi), %mm2 /* V23 */ psubsw %mm0, %mm4 /* V40 */ paddsw %mm4, %mm1 /* V41; free mm0 */ /* moved from the next block */ psllw $1, %mm2 /* t117=t125 */ /* column 0: output butterfly */ /* moved above: * movq %mm6, %mm3 duplicate V25 * movq 8*4(%esi), %mm7 V22 * movq 8*12(%esi), %mm2 V23 * psllw $1, %mm2 t117=t125 */ psubsw %mm1, %mm6 /* tm6 */ paddsw %mm1, %mm3 /* tm8; free mm1 */ movq %mm7, %mm1 /* duplicate V22 */ paddsw %mm5, %mm7 /* tm0 */ movq %mm3, 8*8(%esi) /* tm8; free mm3 */ psubsw %mm5, %mm1 /* tm14; free mm5 */ movq %mm6, 8*6(%esi) /* tm6; free mm6 */ movq %mm2, %mm3 /* duplicate t117=t125 */ movq (%esi), %mm6 /* V24 */ paddsw %mm0, %mm2 /* tm2 */ movq %mm7, (%esi) /* tm0; free mm7 */ psubsw %mm0, %mm3 /* tm12; free mm0 */ movq %mm1, 8*14(%esi) /* tm14; free mm1 */ psllw $1, %mm6 /* t119=t123 */ movq %mm2, 8*2(%esi) /* tm2; free mm2 */ movq %mm6, %mm0 /* duplicate t119=t123 */ movq %mm3, 8*12(%esi) /* tm12; free mm3 */ paddsw %mm4, %mm6 /* tm4 */ /* moved from next block */ movq 8*5(%ecx), %mm1 psubsw %mm4, %mm0 /* tm10; free mm4 */ /* moved from next block */ pmulhw 8*5(%esi), %mm1 /* V5 */ movq %mm6, 8*4(%esi) /* tm4; free mm6 */ movq %mm0, 8*10(%esi) /* tm10; free mm0 */ /* column 1: even part * use V5, V13, V1, V9 to produce V56..V59 */ /* moved to prev block: * movq 8*5(%ecx), %mm1 * pmulhw 8*5(%esi), %mm1 V5 */ movq 8*13(%ecx), %mm7 psllw $1, %mm1 /* t128=t130 */ pmulhw 8*13(%esi), %mm7 /* V13 */ movq %mm1, %mm2 /* duplicate t128=t130 */ movq 8(%ecx), %mm3 pmulhw 8(%esi), %mm3 /* V1 */ movq 8*9(%ecx), %mm5 psubsw %mm7, %mm1 /* V50 */ pmulhw 8*9(%esi), %mm5 /* V9 */ paddsw %mm7, %mm2 /* V51 */ pmulhw x5a825a825a825a82, %mm1 /* 23170 ->V52 */ movq %mm2, %mm6 /* duplicate V51 */ psraw $1, %mm2 /* t138=t144 */ movq %mm3, %mm4 /* duplicate V1 */ psraw $2, %mm6 /* t136 */ paddsw %mm5, %mm3 /* V53 */ psubsw %mm5, %mm4 /* V54 ;mm5 free */ movq %mm3, %mm7 /* duplicate V53 */ /* moved from next block */ movq 8*11(%ecx), %mm0 psraw $1, %mm4 /* t140=t142 */ psubsw %mm6, %mm1 /* V55 ; mm6 free */ paddsw %mm2, %mm3 /* V56 */ movq %mm4, %mm5 /* duplicate t140=t142 */ paddsw %mm1, %mm4 /* V57 */ movq %mm3, 8*5(%esi) /* V56 */ psubsw %mm1, %mm5 /* V58; mm1 free */ movq %mm4, 8*13(%esi) /* V57 */ psubsw %mm2, %mm7 /* V59; mm2 free */ movq %mm5, 8*9(%esi) /* V58 */ /* keep mm7 alive all along the next block * movq %mm7, 8(%esi) V59 * moved above * movq 8*11(%ecx), %mm0 */ pmulhw 8*11(%esi), %mm0 /* V11 */ movq 8*7(%ecx), %mm6 pmulhw 8*7(%esi), %mm6 /* V7 */ movq 8*15(%ecx), %mm4 movq %mm0, %mm3 /* duplicate V11 */ pmulhw 8*15(%esi), %mm4 /* V15 */ movq 8*3(%ecx), %mm5 psllw $1, %mm6 /* t146=t152 */ pmulhw 8*3(%esi), %mm5 /* V3 */ paddsw %mm6, %mm0 /* V63 */ /* note that V15 computation has a correction step: * this is a 'magic' constant that rebiases the results to be closer to the * expected result. this magic constant can be refined to reduce the error * even more by doing the correction step in a later stage when the number * is actually multiplied by 16 */ paddw x0005000200010001, %mm4 psubsw %mm6, %mm3 /* V60 ; free mm6 */ psraw $1, %mm0 /* t154=t156 */ movq %mm3, %mm1 /* duplicate V60 */ pmulhw x539f539f539f539f, %mm1 /* V67 */ movq %mm5, %mm6 /* duplicate V3 */ psraw $2, %mm4 /* t148=t150 */ paddsw %mm4, %mm5 /* V61 */ psubsw %mm4, %mm6 /* V62 ; free mm4 */ movq %mm5, %mm4 /* duplicate V61 */ psllw $1, %mm1 /* t169 */ paddsw %mm0, %mm5 /* V65 -> result */ psubsw %mm0, %mm4 /* V64 ; free mm0 */ pmulhw x5a825a825a825a82, %mm4 /* V68 */ psraw $1, %mm3 /* t158 */ psubsw %mm6, %mm3 /* V66 */ movq %mm5, %mm2 /* duplicate V65 */ pmulhw x61f861f861f861f8, %mm3 /* V70 */ psllw $1, %mm6 /* t165 */ pmulhw x4546454645464546, %mm6 /* V69 */ psraw $1, %mm2 /* t172 */ /* moved from next block */ movq 8*5(%esi), %mm0 /* V56 */ psllw $1, %mm4 /* t174 */ /* moved from next block */ psraw $1, %mm0 /* t177=t188 */ nop psubsw %mm3, %mm6 /* V72 */ psubsw %mm1, %mm3 /* V71 ; free mm1 */ psubsw %mm2, %mm6 /* V73 ; free mm2 */ /* moved from next block */ psraw $1, %mm5 /* t178=t189 */ psubsw %mm6, %mm4 /* V74 */ /* moved from next block */ movq %mm0, %mm1 /* duplicate t177=t188 */ paddsw %mm4, %mm3 /* V75 */ /* moved from next block */ paddsw %mm5, %mm0 /* tm1 */ /* location * 5 - V56 * 13 - V57 * 9 - V58 * X - V59, mm7 * X - V65, mm5 * X - V73, mm6 * X - V74, mm4 * X - V75, mm3 * free mm0, mm1 & mm2 * moved above * movq 8*5(%esi), %mm0 V56 * psllw $1, %mm0 t177=t188 ! new !! * psllw $1, %mm5 t178=t189 ! new !! * movq %mm0, %mm1 duplicate t177=t188 * paddsw %mm5, %mm0 tm1 */ movq 8*13(%esi), %mm2 /* V57 */ psubsw %mm5, %mm1 /* tm15; free mm5 */ movq %mm0, 8(%esi) /* tm1; free mm0 */ psraw $1, %mm7 /* t182=t184 ! new !! */ /* save the store as used directly in the transpose * movq %mm1, 120(%esi) tm15; free mm1 */ movq %mm7, %mm5 /* duplicate t182=t184 */ psubsw %mm3, %mm7 /* tm7 */ paddsw %mm3, %mm5 /* tm9; free mm3 */ movq 8*9(%esi), %mm0 /* V58 */ movq %mm2, %mm3 /* duplicate V57 */ movq %mm7, 8*7(%esi) /* tm7; free mm7 */ psubsw %mm6, %mm3 /* tm13 */ paddsw %mm6, %mm2 /* tm3 ; free mm6 */ /* moved up from the transpose */ movq %mm3, %mm7 /* moved up from the transpose */ punpcklwd %mm1, %mm3 movq %mm0, %mm6 /* duplicate V58 */ movq %mm2, 8*3(%esi) /* tm3; free mm2 */ paddsw %mm4, %mm0 /* tm5 */ psubsw %mm4, %mm6 /* tm11; free mm4 */ /* moved up from the transpose */ punpckhwd %mm1, %mm7 movq %mm0, 8*5(%esi) /* tm5; free mm0 */ /* moved up from the transpose */ movq %mm5, %mm2 /* transpose - M4 part * --------- --------- * | M1 | M2 | | M1'| M3'| * --------- --> --------- * | M3 | M4 | | M2'| M4'| * --------- --------- * Two alternatives: use full mmword approach so the following code can be * scheduled before the transpose is done without stores, or use the faster * half mmword stores (when possible) */ movd %mm3, 8*9+4(%esi) /* MS part of tmt9 */ punpcklwd %mm6, %mm5 movd %mm7, 8*13+4(%esi) /* MS part of tmt13 */ punpckhwd %mm6, %mm2 movd %mm5, 8*9(%esi) /* LS part of tmt9 */ punpckhdq %mm3, %mm5 /* free mm3 */ movd %mm2, 8*13(%esi) /* LS part of tmt13 */ punpckhdq %mm7, %mm2 /* free mm7 */ /* moved up from the M3 transpose */ movq 8*8(%esi), %mm0 /* moved up from the M3 transpose */ movq 8*10(%esi), %mm1 /* moved up from the M3 transpose */ movq %mm0, %mm3 /* shuffle the rest of the data, and write it with 2 mmword writes */ movq %mm5, 8*11(%esi) /* tmt11 */ /* moved up from the M3 transpose */ punpcklwd %mm1, %mm0 movq %mm2, 8*15(%esi) /* tmt15 */ /* moved up from the M3 transpose */ punpckhwd %mm1, %mm3 /* transpose - M3 part * moved up to previous code section * movq 8*8(%esi), %mm0 * movq 8*10(%esi), %mm1 * movq %mm0, %mm3 * punpcklwd %mm1, %mm0 * punpckhwd %mm1, %mm3 */ movq 8*12(%esi), %mm6 movq 8*14(%esi), %mm4 movq %mm6, %mm2 /* shuffle the data and write the lower parts of the transposed in 4 dwords */ punpcklwd %mm4, %mm6 movq %mm0, %mm1 punpckhdq %mm6, %mm1 movq %mm3, %mm7 punpckhwd %mm4, %mm2 /* free mm4 */ punpckldq %mm6, %mm0 /* free mm6 */ /* moved from next block */ movq 8*13(%esi), %mm4 /* tmt13 */ punpckldq %mm2, %mm3 punpckhdq %mm2, %mm7 /* free mm2 */ /* moved from next block */ movq %mm3, %mm5 /* duplicate tmt5 */ /* column 1: even part (after transpose) * moved above * movq %mm3, %mm5 duplicate tmt5 * movq 8*13(%esi), %mm4 tmt13 */ psubsw %mm4, %mm3 /* V134 */ pmulhw x5a825a825a825a82, %mm3 /* 23170 ->V136 */ movq 8*9(%esi), %mm6 /* tmt9 */ paddsw %mm4, %mm5 /* V135 ; mm4 free */ movq %mm0, %mm4 /* duplicate tmt1 */ paddsw %mm6, %mm0 /* V137 */ psubsw %mm6, %mm4 /* V138 ; mm6 free */ psllw $2, %mm3 /* t290 */ psubsw %mm5, %mm3 /* V139 */ movq %mm0, %mm6 /* duplicate V137 */ paddsw %mm5, %mm0 /* V140 */ movq %mm4, %mm2 /* duplicate V138 */ paddsw %mm3, %mm2 /* V141 */ psubsw %mm3, %mm4 /* V142 ; mm3 free */ movq %mm0, 8*9(%esi) /* V140 */ psubsw %mm5, %mm6 /* V143 ; mm5 free */ /* moved from next block */ movq 8*11(%esi), %mm0 /* tmt11 */ movq %mm2, 8*13(%esi) /* V141 */ /* moved from next block */ movq %mm0, %mm2 /* duplicate tmt11 */ /* column 1: odd part (after transpose) */ /* moved up to the prev block * movq 8*11(%esi), %mm0 tmt11 * movq %mm0, %mm2 duplicate tmt11 */ movq 8*15(%esi), %mm5 /* tmt15 */ psubsw %mm7, %mm0 /* V144 */ movq %mm0, %mm3 /* duplicate V144 */ paddsw %mm7, %mm2 /* V147 ; free mm7 */ pmulhw x539f539f539f539f, %mm0 /* 21407-> V151 */ movq %mm1, %mm7 /* duplicate tmt3 */ paddsw %mm5, %mm7 /* V145 */ psubsw %mm5, %mm1 /* V146 ; free mm5 */ psubsw %mm1, %mm3 /* V150 */ movq %mm7, %mm5 /* duplicate V145 */ pmulhw x4546454645464546, %mm1 /* 17734-> V153 */ psubsw %mm2, %mm5 /* V148 */ pmulhw x61f861f861f861f8, %mm3 /* 25080-> V154 */ psllw $2, %mm0 /* t311 */ pmulhw x5a825a825a825a82, %mm5 /* 23170-> V152 */ paddsw %mm2, %mm7 /* V149 ; free mm2 */ psllw $1, %mm1 /* t313 */ nop /* without the nop - freeze here for one clock */ movq %mm3, %mm2 /* duplicate V154 */ psubsw %mm0, %mm3 /* V155 ; free mm0 */ psubsw %mm2, %mm1 /* V156 ; free mm2 */ /* moved from the next block */ movq %mm6, %mm2 /* duplicate V143 */ /* moved from the next block */ movq 8*13(%esi), %mm0 /* V141 */ psllw $1, %mm1 /* t315 */ psubsw %mm7, %mm1 /* V157 (keep V149) */ psllw $2, %mm5 /* t317 */ psubsw %mm1, %mm5 /* V158 */ psllw $1, %mm3 /* t319 */ paddsw %mm5, %mm3 /* V159 */ /* column 1: output butterfly (after transform) * moved to the prev block * movq %mm6, %mm2 duplicate V143 * movq 8*13(%esi), %mm0 V141 */ psubsw %mm3, %mm2 /* V163 */ paddsw %mm3, %mm6 /* V164 ; free mm3 */ movq %mm4, %mm3 /* duplicate V142 */ psubsw %mm5, %mm4 /* V165 ; free mm5 */ movq %mm2, (%esp) /* out7 */ psraw $4, %mm6 psraw $4, %mm4 paddsw %mm5, %mm3 /* V162 */ movq 8*9(%esi), %mm2 /* V140 */ movq %mm0, %mm5 /* duplicate V141 */ /* in order not to perculate this line up, * we read 72(%esi) very near to this location */ movq %mm6, 8*9(%esi) /* out9 */ paddsw %mm1, %mm0 /* V161 */ movq %mm3, 8(%esp) /* out5 */ psubsw %mm1, %mm5 /* V166 ; free mm1 */ movq %mm4, 8*11(%esi) /* out11 */ psraw $4, %mm5 movq %mm0, 16(%esp) /* out3 */ movq %mm2, %mm4 /* duplicate V140 */ movq %mm5, 8*13(%esi) /* out13 */ paddsw %mm7, %mm2 /* V160 */ /* moved from the next block */ movq 8(%esi), %mm0 psubsw %mm7, %mm4 /* V167 ; free mm7 */ /* moved from the next block */ movq 8*3(%esi), %mm7 psraw $4, %mm4 movq %mm2, 24(%esp) /* out1 */ /* moved from the next block */ movq %mm0, %mm1 movq %mm4, 8*15(%esi) /* out15 */ /* moved from the next block */ punpcklwd %mm7, %mm0 /* transpose - M2 parts * moved up to the prev block * movq 8(%esi), %mm0 * movq 8*3(%esi), %mm7 * movq %mm0, %mm1 * punpcklwd %mm7, %mm0 */ movq 8*5(%esi), %mm5 punpckhwd %mm7, %mm1 movq 8*7(%esi), %mm4 movq %mm5, %mm3 /* shuffle the data and write the lower parts of the trasposed in 4 dwords */ movd %mm0, 8*8(%esi) /* LS part of tmt8 */ punpcklwd %mm4, %mm5 movd %mm1, 8*12(%esi) /* LS part of tmt12 */ punpckhwd %mm4, %mm3 movd %mm5, 8*8+4(%esi) /* MS part of tmt8 */ punpckhdq %mm5, %mm0 /* tmt10 */ movd %mm3, 8*12+4(%esi) /* MS part of tmt12 */ punpckhdq %mm3, %mm1 /* tmt14 */ /* transpose - M1 parts */ movq (%esi), %mm7 movq 8*2(%esi), %mm2 movq %mm7, %mm6 movq 8*4(%esi), %mm5 punpcklwd %mm2, %mm7 movq 8*6(%esi), %mm4 punpckhwd %mm2, %mm6 /* free mm2 */ movq %mm5, %mm3 punpcklwd %mm4, %mm5 punpckhwd %mm4, %mm3 /* free mm4 */ movq %mm7, %mm2 movq %mm6, %mm4 punpckldq %mm5, %mm7 /* tmt0 */ punpckhdq %mm5, %mm2 /* tmt2 ; free mm5 */ /* shuffle the rest of the data, and write it with 2 mmword writes */ punpckldq %mm3, %mm6 /* tmt4 */ /* moved from next block */ movq %mm2, %mm5 /* duplicate tmt2 */ punpckhdq %mm3, %mm4 /* tmt6 ; free mm3 */ /* moved from next block */ movq %mm0, %mm3 /* duplicate tmt10 */ /* column 0: odd part (after transpose) *moved up to prev block * movq %mm0, %mm3 duplicate tmt10 * movq %mm2, %mm5 duplicate tmt2 */ psubsw %mm4, %mm0 /* V110 */ paddsw %mm4, %mm3 /* V113 ; free mm4 */ movq %mm0, %mm4 /* duplicate V110 */ paddsw %mm1, %mm2 /* V111 */ pmulhw x539f539f539f539f, %mm0 /* 21407-> V117 */ psubsw %mm1, %mm5 /* V112 ; free mm1 */ psubsw %mm5, %mm4 /* V116 */ movq %mm2, %mm1 /* duplicate V111 */ pmulhw x4546454645464546, %mm5 /* 17734-> V119 */ psubsw %mm3, %mm2 /* V114 */ pmulhw x61f861f861f861f8, %mm4 /* 25080-> V120 */ paddsw %mm3, %mm1 /* V115 ; free mm3 */ pmulhw x5a825a825a825a82, %mm2 /* 23170-> V118 */ psllw $2, %mm0 /* t266 */ movq %mm1, (%esi) /* save V115 */ psllw $1, %mm5 /* t268 */ psubsw %mm4, %mm5 /* V122 */ psubsw %mm0, %mm4 /* V121 ; free mm0 */ psllw $1, %mm5 /* t270 */ psubsw %mm1, %mm5 /* V123 ; free mm1 */ psllw $2, %mm2 /* t272 */ psubsw %mm5, %mm2 /* V124 (keep V123) */ psllw $1, %mm4 /* t274 */ movq %mm5, 8*2(%esi) /* save V123 ; free mm5 */ paddsw %mm2, %mm4 /* V125 (keep V124) */ /* column 0: even part (after transpose) */ movq 8*12(%esi), %mm0 /* tmt12 */ movq %mm6, %mm3 /* duplicate tmt4 */ psubsw %mm0, %mm6 /* V100 */ paddsw %mm0, %mm3 /* V101 ; free mm0 */ pmulhw x5a825a825a825a82, %mm6 /* 23170 ->V102 */ movq %mm7, %mm5 /* duplicate tmt0 */ movq 8*8(%esi), %mm1 /* tmt8 */ paddsw %mm1, %mm7 /* V103 */ psubsw %mm1, %mm5 /* V104 ; free mm1 */ movq %mm7, %mm0 /* duplicate V103 */ psllw $2, %mm6 /* t245 */ paddsw %mm3, %mm7 /* V106 */ movq %mm5, %mm1 /* duplicate V104 */ psubsw %mm3, %mm6 /* V105 */ psubsw %mm3, %mm0 /* V109; free mm3 */ paddsw %mm6, %mm5 /* V107 */ psubsw %mm6, %mm1 /* V108 ; free mm6 */ /* column 0: output butterfly (after transform) */ movq %mm1, %mm3 /* duplicate V108 */ paddsw %mm2, %mm1 /* out4 */ psraw $4, %mm1 psubsw %mm2, %mm3 /* out10 ; free mm2 */ psraw $4, %mm3 movq %mm0, %mm6 /* duplicate V109 */ movq %mm1, 8*4(%esi) /* out4 ; free mm1 */ psubsw %mm4, %mm0 /* out6 */ movq %mm3, 8*10(%esi) /* out10 ; free mm3 */ psraw $4, %mm0 paddsw %mm4, %mm6 /* out8 ; free mm4 */ movq %mm7, %mm1 /* duplicate V106 */ movq %mm0, 8*6(%esi) /* out6 ; free mm0 */ psraw $4, %mm6 movq (%esi), %mm4 /* V115 */ movq %mm6, 8*8(%esi) /* out8 ; free mm6 */ movq %mm5, %mm2 /* duplicate V107 */ movq 8*2(%esi), %mm3 /* V123 */ paddsw %mm4, %mm7 /* out0 */ /* moved up from next block */ movq 16(%esp), %mm0 psraw $4, %mm7 /* moved up from next block */ movq 8(%esp), %mm6 psubsw %mm4, %mm1 /* out14 ; free mm4 */ paddsw %mm3, %mm5 /* out2 */ psraw $4, %mm1 movq %mm7, (%esi) /* out0 ; free mm7 */ psraw $4, %mm5 movq %mm1, 8*14(%esi) /* out14 ; free mm1 */ psubsw %mm3, %mm2 /* out12 ; free mm3 */ movq %mm5, 8*2(%esi) /* out2 ; free mm5 */ psraw $4, %mm2 /* moved up to the prev block */ movq (%esp), %mm4 /* moved up to the prev block */ psraw $4, %mm0 movq %mm2, 8*12(%esi) /* out12 ; free mm2 */ /* moved up to the prev block */ psraw $4, %mm6 /* move back the data to its correct place * moved up to the prev block * movq 16(%esp), %mm0 * movq 8(%esp), %mm6 * movq (%esp), %mm4 * psraw $4, %mm0 * psraw $4, %mm6 */ movq 24(%esp), %mm1 psraw $4, %mm4 movq %mm0, 8*3(%esi) /* out3 */ psraw $4, %mm1 movq %mm6, 8*5(%esi) /* out5 */ movq %mm4, 8*7(%esi) /* out7 */ movq %mm1, 8(%esi) /* out1 */ popl %edi /* Pop off the temp variables */ popl %edi popl %edi popl %edi popl %edi popl %edi popl %edi popl %edi popl %edi /* Pop off the old variables */ popl %esi popl %edx popl %ecx popl %ebx movl %ebp, %esp popl %ebp ret .Lfe1: .size IDCT_mmx,.Lfe1-IDCT_mmx libmpeg3-1.5.4/video/mmxtest.c0000644000175000017500000000137107742725646016437 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include #include int mpeg3_mmx_test() { int result = 0; FILE *proc; char string[MPEG3_STRLEN]; #ifdef HAVE_MMX if(!(proc = fopen(MPEG3_PROC_CPUINFO, "r"))) { fprintf(stderr, "mpeg3_mmx_test: failed to open /proc/cpuinfo\n"); return 0; } while(!feof(proc)) { fgets(string, MPEG3_STRLEN, proc); /* Got the flags line */ if(!strncasecmp(string, "flags", 5)) { char *needle; needle = strstr(string, "mmx"); if(!needle) { fclose(proc); return 0; } if(!strncasecmp(needle, "mmx", 3)) { fclose(proc); return 1; } } } fclose(proc); #endif return 0; } libmpeg3-1.5.4/video/motion.c0000644000175000017500000001256507742725646016252 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include "vlc.h" #include /* calculate motion vector component */ void mpeg3video_calc_mv(int *pred, int r_size, int motion_code, int motion_r, int full_pel_vector) { int lim = 16 << r_size; int vec = full_pel_vector ? (*pred >> 1) : (*pred); if(motion_code > 0) { vec += ((motion_code - 1) << r_size) + motion_r + 1; if(vec >= lim) vec -= lim + lim; } else if(motion_code < 0) { vec -= ((-motion_code - 1) << r_size) + motion_r + 1; if(vec < -lim) vec += lim + lim; } *pred = full_pel_vector ? (vec << 1) : vec; } /* int *dmvector, * differential motion vector * int mvx, int mvy * decoded mv components (always in field format) * */ void mpeg3video_calc_dmv(mpeg3video_t *video, int DMV[][2], int *dmvector, int mvx, int mvy) { if(video->pict_struct == FRAME_PICTURE) { if(video->topfirst) { /* vector for prediction of top field from bottom field */ DMV[0][0] = ((mvx + (mvx>0)) >> 1) + dmvector[0]; DMV[0][1] = ((mvy + (mvy>0)) >> 1) + dmvector[1] - 1; /* vector for prediction of bottom field from top field */ DMV[1][0] = ((3 * mvx + (mvx > 0)) >> 1) + dmvector[0]; DMV[1][1] = ((3 * mvy + (mvy > 0)) >> 1) + dmvector[1] + 1; } else { /* vector for prediction of top field from bottom field */ DMV[0][0] = ((3 * mvx + (mvx>0)) >> 1) + dmvector[0]; DMV[0][1] = ((3 * mvy + (mvy>0)) >> 1) + dmvector[1] - 1; /* vector for prediction of bottom field from top field */ DMV[1][0] = ((mvx + (mvx>0)) >> 1) + dmvector[0]; DMV[1][1] = ((mvy + (mvy>0)) >> 1) + dmvector[1] + 1; } } else { /* vector for prediction from field of opposite 'parity' */ DMV[0][0] = ((mvx + (mvx > 0)) >> 1) + dmvector[0]; DMV[0][1] = ((mvy + (mvy > 0)) >> 1) + dmvector[1]; /* correct for vertical field shift */ if(video->pict_struct == TOP_FIELD) DMV[0][1]--; else DMV[0][1]++; } } int mpeg3video_get_mv(mpeg3_slice_t *slice) { int code; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; if(mpeg3slice_getbit(slice_buffer)) { return 0; } if((code = mpeg3slice_showbits9(slice_buffer)) >= 64) { code >>= 6; mpeg3slice_flushbits(slice_buffer, mpeg3_MVtab0[code].len); return mpeg3slice_getbit(slice_buffer) ? -mpeg3_MVtab0[code].val : mpeg3_MVtab0[code].val; } if(code >= 24) { code >>= 3; mpeg3slice_flushbits(slice_buffer, mpeg3_MVtab1[code].len); return mpeg3slice_getbit(slice_buffer) ? -mpeg3_MVtab1[code].val : mpeg3_MVtab1[code].val; } if((code -= 12) < 0) { /* fprintf(stdout,"mpeg3video_get_mv: invalid motion_vector code\n"); */ slice->fault = 1; return 1; } mpeg3slice_flushbits(slice_buffer, mpeg3_MVtab2[code].len); return mpeg3slice_getbit(slice_buffer) ? -mpeg3_MVtab2[code].val : mpeg3_MVtab2[code].val; } /* get differential motion vector (for dual prime prediction) */ int mpeg3video_get_dmv(mpeg3_slice_t *slice) { mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; if(mpeg3slice_getbit(slice_buffer)) { return mpeg3slice_getbit(slice_buffer) ? -1 : 1; } else { return 0; } } /* get and decode motion vector and differential motion vector */ void mpeg3video_motion_vector(mpeg3_slice_t *slice, mpeg3video_t *video, int *PMV, int *dmvector, int h_r_size, int v_r_size, int dmv, int mvscale, int full_pel_vector) { int motion_r; int motion_code = mpeg3video_get_mv(slice); mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; if(slice->fault) return; motion_r = (h_r_size != 0 && motion_code != 0) ? mpeg3slice_getbits(slice_buffer, h_r_size) : 0; mpeg3video_calc_mv(&PMV[0], h_r_size, motion_code, motion_r, full_pel_vector); if(dmv) dmvector[0] = mpeg3video_get_dmv(slice); motion_code = mpeg3video_get_mv(slice); if(slice->fault) return; motion_r = (v_r_size != 0 && motion_code != 0) ? mpeg3slice_getbits(slice_buffer, v_r_size) : 0; /* DIV 2 */ if(mvscale) PMV[1] >>= 1; mpeg3video_calc_mv(&PMV[1], v_r_size, motion_code, motion_r, full_pel_vector); if(mvscale) PMV[1] <<= 1; if(dmv) dmvector[1] = mpeg3video_get_dmv(slice); } int mpeg3video_motion_vectors(mpeg3_slice_t *slice, mpeg3video_t *video, int PMV[2][2][2], int dmvector[2], int mv_field_sel[2][2], int s, int mv_count, int mv_format, int h_r_size, int v_r_size, int dmv, int mvscale) { int result = 0; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; if(mv_count == 1) { if(mv_format == MV_FIELD && !dmv) { mv_field_sel[1][s] = mv_field_sel[0][s] = mpeg3slice_getbit(slice_buffer); } mpeg3video_motion_vector(slice, video, PMV[0][s], dmvector, h_r_size, v_r_size, dmv, mvscale, 0); if(slice->fault) return 1; /* update other motion vector predictors */ PMV[1][s][0] = PMV[0][s][0]; PMV[1][s][1] = PMV[0][s][1]; } else { mv_field_sel[0][s] = mpeg3slice_getbit(slice_buffer); mpeg3video_motion_vector(slice, video, PMV[0][s], dmvector, h_r_size, v_r_size, dmv, mvscale, 0); if(slice->fault) return 1; mv_field_sel[1][s] = mpeg3slice_getbit(slice_buffer); mpeg3video_motion_vector(slice, video, PMV[1][s], dmvector, h_r_size, v_r_size, dmv, mvscale, 0); if(slice->fault) return 1; } return 0; } libmpeg3-1.5.4/video/mpeg3video.c0000644000175000017500000005030607766460756017006 0ustar enderender00000000000000#include "../libmpeg3.h" #include "../mpeg3private.h" #include "../mpeg3protos.h" #include "mpeg3video.h" #include "mpeg3videoprotos.h" #include #include // "½Åµ¿ÈÆ" unsigned char mpeg3_zig_zag_scan_mmx[64] = { 0*8+0 /* 0*/, 1*8+0 /* 1*/, 0*8+1 /* 8*/, 0*8+2 /*16*/, 1*8+1 /* 9*/, 2*8+0 /* 2*/, 3*8+0 /* 3*/, 2*8+1 /*10*/, 1*8+2 /*17*/, 0*8+3 /*24*/, 0*8+4 /*32*/, 1*8+3 /*25*/, 2*8+2 /*18*/, 3*8+1 /*11*/, 4*8+0 /* 4*/, 5*8+0 /* 5*/, 4*8+1 /*12*/, 3*8+2 /*19*/, 2*8+3 /*26*/, 1*8+4 /*33*/, 0*8+5 /*40*/, 0*8+6 /*48*/, 1*8+5 /*41*/, 2*8+4 /*34*/, 3*8+3 /*27*/, 4*8+2 /*20*/, 5*8+1 /*13*/, 6*8+0 /* 6*/, 7*8+0 /* 7*/, 6*8+1 /*14*/, 5*8+2 /*21*/, 4*8+3 /*28*/, 3*8+4 /*35*/, 2*8+5 /*42*/, 1*8+6 /*49*/, 0*8+7 /*56*/, 1*8+7 /*57*/, 2*8+6 /*50*/, 3*8+5 /*43*/, 4*8+4 /*36*/, 5*8+3 /*29*/, 6*8+2 /*22*/, 7*8+1 /*15*/, 7*8+2 /*23*/, 6*8+3 /*30*/, 5*8+4 /*37*/, 4*8+5 /*44*/, 3*8+6 /*51*/, 2*8+7 /*58*/, 3*8+7 /*59*/, 4*8+6 /*52*/, 5*8+5 /*45*/, 6*8+4 /*38*/, 7*8+3 /*31*/, 7*8+4 /*39*/, 6*8+5 /*46*/, 5*8+6 /*53*/, 4*8+7 /*60*/, 5*8+7 /*61*/, 6*8+6 /*54*/, 7*8+5 /*47*/, 7*8+6 /*55*/, 6*8+7 /*62*/, 7*8+7 /*63*/ }; /* alternate scan */ unsigned char mpeg3_alternate_scan_mmx[64] = { 0*8+0 /*0 */, 0*8+1 /* 8*/, 0*8+2 /*16*/, 0*8+3 /*24*/, 1*8+0 /* 1*/, 1*8+1 /* 9*/, 2*8+0 /* 2*/, 2*8+1 /*10*/, 1*8+2 /*17*/, 1*8+3 /*25*/, 0*8+4 /*32*/, 0*8+5 /*40*/, 0*8+6 /*48*/, 0*8+7 /*56*/, 1*8+7 /*57*/, 1*8+6 /*49*/, 1*8+5 /*41*/, 1*8+4 /*33*/, 2*8+3 /*26*/, 2*8+2 /*18*/, 3*8+0 /* 3*/, 3*8+1 /*11*/, 4*8+0 /* 4*/, 4*8+1 /*12*/, 3*8+2 /*19*/, 3*8+3 /*27*/, 2*8+4 /*34*/, 2*8+5 /*42*/, 2*8+6 /*50*/, 2*8+7 /*58*/, 3*8+4 /*35*/, 3*8+5 /*43*/, 3*8+6 /*51*/, 3*8+7 /*59*/, 4*8+2 /*20*/, 4*8+3 /*28*/, 5*8+0 /* 5*/, 5*8+1 /*13*/, 6*8+0 /* 6*/, 6*8+1 /*14*/, 5*8+2 /*21*/, 5*8+3 /*29*/, 4*8+4 /*36*/, 4*8+5 /*44*/, 4*8+6 /*52*/, 4*8+7 /*60*/, 5*8+4 /*37*/, 5*8+5 /*45*/, 5*8+6 /*53*/, 5*8+7 /*61*/, 6*8+2 /*22*/, 6*8+3 /*30*/, 7*8+0 /* 7*/, 7*8+1 /*15*/, 7*8+2 /*23*/, 7*8+3 /*31*/, 6*8+4 /*38*/, 6*8+5 /*46*/, 6*8+6 /*54*/, 6*8+7 /*62*/, 7*8+4 /*39*/, 7*8+5 /*47*/, 7*8+6 /*55*/, 7*8+7 /*63*/ }; /* zig-zag scan */ unsigned char mpeg3_zig_zag_scan_nommx[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; /* alternate scan */ unsigned char mpeg3_alternate_scan_nommx[64] = { 0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49, 41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43, 51, 59, 20, 28, 5, 13, 6, 14, 21, 29, 36, 44, 52, 60, 37, 45, 53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63 }; /* default intra quantization matrix */ unsigned char mpeg3_default_intra_quantizer_matrix[64] = { 8, 16, 19, 22, 26, 27, 29, 34, 16, 16, 22, 24, 27, 29, 34, 37, 19, 22, 26, 27, 29, 34, 34, 38, 22, 22, 26, 27, 29, 34, 37, 40, 22, 26, 27, 29, 32, 35, 40, 48, 26, 27, 29, 32, 35, 40, 48, 58, 26, 27, 29, 34, 38, 46, 56, 69, 27, 29, 35, 38, 46, 56, 69, 83 }; unsigned char mpeg3_non_linear_mquant_table[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 44, 48, 52, 56, 64, 72, 80, 88, 96, 104, 112 }; double mpeg3_frame_rate_table[16] = { 0.0, /* Pad */ (double)24000.0/1001.0, /* Official frame rates */ (double)24.0, (double)25.0, (double)30000.0/1001.0, (double)30.0, (double)50.0, (double)60000.0/1001.0, (double)60.0, 1, /* Unofficial economy rates */ 5, 10, 12, 15, 0, 0, }; int mpeg3video_initdecoder(mpeg3video_t *video) { int blk_cnt_tab[3] = {6, 8, 12}; int cc; int i; long size[4], padding[2]; /* Size of Y, U, and V buffers */ if(!video->mpeg2) { /* force MPEG-1 parameters */ video->prog_seq = 1; video->prog_frame = 1; video->pict_struct = FRAME_PICTURE; video->frame_pred_dct = 1; video->chroma_format = CHROMA420; video->matrix_coefficients = 5; } /* Get dimensions rounded to nearest multiple of coded macroblocks */ video->mb_width = (video->horizontal_size + 15) / 16; video->mb_height = (video->mpeg2 && !video->prog_seq) ? (2 * ((video->vertical_size + 31) / 32)) : ((video->vertical_size + 15) / 16); video->coded_picture_width = 16 * video->mb_width; video->coded_picture_height = 16 * video->mb_height; video->chrom_width = (video->chroma_format == CHROMA444) ? video->coded_picture_width : (video->coded_picture_width >> 1); video->chrom_height = (video->chroma_format != CHROMA420) ? video->coded_picture_height : (video->coded_picture_height >> 1); video->blk_cnt = blk_cnt_tab[video->chroma_format - 1]; /* Get sizes of YUV buffers */ padding[0] = 16 * video->coded_picture_width; size[0] = video->coded_picture_width * video->coded_picture_height + padding[0] * 2; padding[1] = 16 * video->chrom_width; size[1] = video->chrom_width * video->chrom_height + 2 * padding[1]; size[2] = (video->llw * video->llh); size[3] = (video->llw * video->llh) / 4; /* Allocate contiguous fragments for YUV buffers for hardware YUV decoding */ video->yuv_buffer[0] = (unsigned char*)calloc(1, (size[0] + padding[0]) + 2 * (size[1] + padding[1])); video->yuv_buffer[1] = (unsigned char*)calloc(1, (size[0] + padding[0]) + 2 * (size[1] + padding[1])); video->yuv_buffer[2] = (unsigned char*)calloc(1, (size[0] + padding[0]) + 2 * (size[1] + padding[1])); if(video->scalable_mode == SC_SPAT) { video->yuv_buffer[3] = (unsigned char*)calloc(1, size[2] + 2 * size[3]); video->yuv_buffer[4] = (unsigned char*)calloc(1, size[2] + 2 * size[3]); } /* Direct pointers to areas of contiguous fragments in YVU order per Microsoft */ for(cc = 0; cc < 3; cc++) { video->llframe0[cc] = 0; video->llframe1[cc] = 0; video->newframe[cc] = 0; } video->refframe[0] = video->yuv_buffer[0]; video->oldrefframe[0] = video->yuv_buffer[1]; video->auxframe[0] = video->yuv_buffer[2]; video->refframe[2] = video->yuv_buffer[0] + size[0] + padding[0]; video->oldrefframe[2] = video->yuv_buffer[1] + size[0] + padding[0]; video->auxframe[2] = video->yuv_buffer[2] + size[0] + padding[0]; video->refframe[1] = video->yuv_buffer[0] + size[0] + padding[0] + size[1] + padding[1]; video->oldrefframe[1] = video->yuv_buffer[1] + size[0] + padding[0] + size[1] + padding[1]; video->auxframe[1] = video->yuv_buffer[2] + size[0] + padding[0] + size[1] + padding[1]; if(video->scalable_mode == SC_SPAT) { /* this assumes lower layer is 4:2:0 */ video->llframe0[0] = video->yuv_buffer[3] + padding[0] ; video->llframe1[0] = video->yuv_buffer[4] + padding[0] ; video->llframe0[2] = video->yuv_buffer[3] + padding[1] + size[2] ; video->llframe1[2] = video->yuv_buffer[4] + padding[1] + size[2] ; video->llframe0[1] = video->yuv_buffer[3] + padding[1] + size[2] + size[3]; video->llframe1[1] = video->yuv_buffer[4] + padding[1] + size[2] + size[3]; } /* Initialize the YUV tables for software YUV decoding */ video->cr_to_r = malloc(sizeof(long) * 256); video->cr_to_g = malloc(sizeof(long) * 256); video->cb_to_g = malloc(sizeof(long) * 256); video->cb_to_b = malloc(sizeof(long) * 256); video->cr_to_r_ptr = video->cr_to_r + 128; video->cr_to_g_ptr = video->cr_to_g + 128; video->cb_to_g_ptr = video->cb_to_g + 128; video->cb_to_b_ptr = video->cb_to_b + 128; for(i = -128; i < 128; i++) { video->cr_to_r_ptr[i] = (long)( 1.371 * 65536 * i); video->cr_to_g_ptr[i] = (long)(-0.698 * 65536 * i); video->cb_to_g_ptr[i] = (long)(-0.336 * 65536 * i); video->cb_to_b_ptr[i] = (long)( 1.732 * 65536 * i); } return 0; } int mpeg3video_deletedecoder(mpeg3video_t *video) { int i, padding; free(video->yuv_buffer[0]); free(video->yuv_buffer[1]); free(video->yuv_buffer[2]); if(video->llframe0[0]) { free(video->yuv_buffer[3]); free(video->yuv_buffer[4]); } free(video->cr_to_r); free(video->cr_to_g); free(video->cb_to_g); free(video->cb_to_b); return 0; } void mpeg3video_init_scantables(mpeg3video_t *video) { #ifdef HAVE_MMX if(video->have_mmx) { video->mpeg3_zigzag_scan_table = mpeg3_zig_zag_scan_mmx; video->mpeg3_alternate_scan_table = mpeg3_alternate_scan_mmx; } else #endif { video->mpeg3_zigzag_scan_table = mpeg3_zig_zag_scan_nommx; video->mpeg3_alternate_scan_table = mpeg3_alternate_scan_nommx; } } mpeg3video_t* mpeg3video_allocate_struct(mpeg3_t *file, mpeg3_vtrack_t *track) { int i; mpeg3video_t *video = calloc(1, sizeof(mpeg3video_t)); pthread_mutexattr_t mutex_attr; video->file = file; video->track = track; video->vstream = mpeg3bits_new_stream(file, track->demuxer); //printf("mpeg3video_allocate_struct %d\n", mpeg3bits_eof(video->vstream)); video->last_number = -1; /* First frame is all green */ video->framenum = -1; video->have_mmx = file->have_mmx; video->byte_seek = -1; video->frame_seek = -1; mpeg3video_init_scantables(video); mpeg3video_init_output(); pthread_mutexattr_init(&mutex_attr); // pthread_mutexattr_setkind_np(&mutex_attr, PTHREAD_MUTEX_FAST_NP); pthread_mutex_init(&(video->test_lock), &mutex_attr); pthread_mutex_init(&(video->slice_lock), &mutex_attr); return video; } int mpeg3video_delete_struct(mpeg3video_t *video) { int i; mpeg3bits_delete_stream(video->vstream); pthread_mutex_destroy(&(video->test_lock)); pthread_mutex_destroy(&(video->slice_lock)); if(video->x_table) { free(video->x_table); free(video->y_table); } if(video->total_slice_decoders) { for(i = 0; i < video->total_slice_decoders; i++) mpeg3_delete_slice_decoder(&(video->slice_decoders[i])); } for(i = 0; i < video->slice_buffers_initialized; i++) mpeg3_delete_slice_buffer(&(video->slice_buffers[i])); free(video); return 0; } int mpeg3video_read_frame_backend(mpeg3video_t *video, int skip_bframes) { int result = 0; int got_top = 0, got_bottom = 0; int i = 0; do { if(mpeg3bits_eof(video->vstream)) result = 1; if(!result) result = mpeg3video_get_header(video, 0); /* skip_bframes is the number of bframes we can skip successfully. */ /* This is in case a skipped B-frame is repeated and the second repeat happens */ /* to be a B frame we need. */ video->skip_bframes = skip_bframes; if(!result) result = mpeg3video_getpicture(video, video->framenum); if(video->pict_struct == TOP_FIELD) { got_top == 1; } else if(video->pict_struct == BOTTOM_FIELD) { got_bottom = 1; video->secondfield = 0; } else if(video->pict_struct == FRAME_PICTURE) { got_top = got_bottom = 1; } i++; }while(i < 2 && !got_bottom && video->framenum >= 0); // The way they do field based encoding, // the I frames have the top field but both the I frame and // subsequent P frame make the keyframe. #ifdef HAVE_MMX if(video->have_mmx) __asm__ __volatile__ ("emms"); #endif if(!result) { video->last_number = video->framenum; video->framenum++; } //printf("mpeg3video_read_frame_backend 100\n"); return result; } int* mpeg3video_get_scaletable(int input_w, int output_w) { int *result = malloc(sizeof(int) * output_w); float i; float scale = (float)input_w / output_w; for(i = 0; i < output_w; i++) { result[(int)i] = (int)(scale * i); } return result; } /* Get the first I frame. */ int mpeg3video_get_firstframe(mpeg3video_t *video) { int result = 0; video->repeat_count = video->current_repeat = 0; result = mpeg3video_read_frame_backend(video, 0); return result; } static long gop_to_frame(mpeg3video_t *video, mpeg3_timecode_t *gop_timecode) { int hour, minute, second, frame, fps; long result; // Mirror of what mpeg2enc does fps = (int)(video->frame_rate + 0.5); hour = gop_timecode->hour; minute = gop_timecode->minute; second = gop_timecode->second; frame = gop_timecode->frame; result = (long)hour * 60 * 60 * fps + minute * 60 * fps + second * fps + frame; return result; } /* ======================================================================= */ /* ENTRY POINTS */ /* ======================================================================= */ mpeg3video_t* mpeg3video_new(mpeg3_t *file, mpeg3_vtrack_t *track) { mpeg3video_t *video; mpeg3_bits_t *bitstream; mpeg3_demuxer_t *demuxer; int result = 0; video = mpeg3video_allocate_struct(file, track); bitstream = video->vstream; demuxer = bitstream->demuxer; // Get encoding parameters from stream result = mpeg3video_get_header(video, 1); if(!result) { int hour, minute, second, frame; int gop_found; mpeg3video_initdecoder(video); video->decoder_initted = 1; track->width = video->horizontal_size; track->height = video->vertical_size; track->frame_rate = video->frame_rate; /* Try to get the length of the file from GOP's */ if(!track->frame_offsets) { if(file->is_video_stream) { /* Load the first GOP */ mpeg3bits_seek_byte(bitstream, 0); result = mpeg3video_next_code(bitstream, MPEG3_GOP_START_CODE); if(!result) mpeg3bits_getbits(bitstream, 32); if(!result) result = mpeg3video_getgophdr(video); hour = video->gop_timecode.hour; minute = video->gop_timecode.minute; second = video->gop_timecode.second; frame = video->gop_timecode.frame; video->first_frame = gop_to_frame(video, &video->gop_timecode); /* * video->first_frame = (long)(hour * 3600 * video->frame_rate + * minute * 60 * video->frame_rate + * second * video->frame_rate + * frame); */ /* GOPs are supposed to have 16 frames */ video->frames_per_gop = 16; /* Read the last GOP in the file by seeking backward. */ mpeg3demux_seek_byte(demuxer, mpeg3demux_movie_size(demuxer)); mpeg3demux_start_reverse(demuxer); result = mpeg3video_prev_code(demuxer, MPEG3_GOP_START_CODE); mpeg3demux_start_forward(demuxer); mpeg3bits_reset(bitstream); mpeg3bits_getbits(bitstream, 8); if(!result) result = mpeg3video_getgophdr(video); hour = video->gop_timecode.hour; minute = video->gop_timecode.minute; second = video->gop_timecode.second; frame = video->gop_timecode.frame; video->last_frame = gop_to_frame(video, &video->gop_timecode); /* * video->last_frame = (long)((double)hour * 3600 * video->frame_rate + * minute * 60 * video->frame_rate + * second * video->frame_rate + * frame); */ //printf("mpeg3video_new 3 %p\n", video); /* Count number of frames to end */ while(!result) { result = mpeg3video_next_code(bitstream, MPEG3_PICTURE_START_CODE); if(!result) { mpeg3bits_getbyte_noptr(bitstream); video->last_frame++; } } track->total_frames = video->last_frame - video->first_frame + 1; //printf("mpeg3video_new 3 %ld\n", track->total_frames); mpeg3bits_seek_byte(video->vstream, 0); } else // Try to get the length of the file from the multiplexing. // Need a table of contents { /* * video->first_frame = 0; * track->total_frames = video->last_frame = * (long)(mpeg3demux_length(video->vstream->demuxer) * * video->frame_rate); * video->first_frame = 0; */ } } else // Get length from table of contents { track->total_frames = track->total_frame_offsets; } video->maxframe = track->total_frames; video->repeat_count = 0; //printf("mpeg3video_new 2\n"); mpeg3bits_seek_byte(video->vstream, 0); //printf("mpeg3video_new 3\n"); mpeg3video_get_firstframe(video); } else { mpeg3video_delete(video); video = 0; } //printf("mpeg3video_new 4\n"); return video; } int mpeg3video_delete(mpeg3video_t *video) { if(video->decoder_initted) { mpeg3video_deletedecoder(video); } mpeg3video_delete_struct(video); return 0; } int mpeg3video_set_cpus(mpeg3video_t *video, int cpus) { return 0; } int mpeg3video_set_mmx(mpeg3video_t *video, int use_mmx) { video->have_mmx = use_mmx; mpeg3video_init_scantables(video); return 0; } /* Read all the way up to and including the next picture start code */ int mpeg3video_read_raw(mpeg3video_t *video, unsigned char *output, long *size, long max_size) { u_int32_t code = 0; mpeg3_bits_t *vstream = video->vstream; *size = 0; while(code != MPEG3_PICTURE_START_CODE && code != MPEG3_SEQUENCE_END_CODE && *size < max_size && !mpeg3bits_eof(vstream)) { code <<= 8; *output = mpeg3bits_getbyte_noptr(vstream); code |= *output++; (*size)++; } return mpeg3bits_eof(vstream); } int mpeg3video_read_frame(mpeg3video_t *video, long frame_number, unsigned char **output_rows, int in_x, int in_y, int in_w, int in_h, int out_w, int out_h, int color_model) { int result = 0; video->want_yvu = 0; video->output_rows = output_rows; video->color_model = color_model; /* Get scaling tables */ if(video->out_w != out_w || video->out_h != out_h || video->in_w != in_w || video->in_h != in_h || video->in_x != in_x || video->in_y != in_y) { if(video->x_table) { free(video->x_table); free(video->y_table); video->x_table = 0; video->y_table = 0; } } video->out_w = out_w; video->out_h = out_h; video->in_w = in_w; video->in_h = in_h; video->in_x = in_x; video->in_y = in_y; if(!video->x_table) { video->x_table = mpeg3video_get_scaletable(video->in_w, video->out_w); video->y_table = mpeg3video_get_scaletable(video->in_h, video->out_h); } //printf("mpeg3video_read_frame 1 %d\n", video->framenum); // Only decode if it's a different frame if(video->frame_seek < 0 || video->last_number < 0 || video->frame_seek != video->last_number) { if(!result) result = mpeg3video_seek(video); if(!result) result = mpeg3video_read_frame_backend(video, 0); } else { video->framenum = video->frame_seek + 1; video->last_number = video->frame_seek; video->frame_seek = -1; } if(video->output_src) mpeg3video_present_frame(video); return result; } int mpeg3video_read_yuvframe(mpeg3video_t *video, long frame_number, char *y_output, char *u_output, char *v_output, int in_x, int in_y, int in_w, int in_h) { int result = 0; //printf("mpeg3video_read_yuvframe 1 %d\n", video->framenum); video->want_yvu = 1; video->y_output = y_output; video->u_output = u_output; video->v_output = v_output; video->in_x = in_x; video->in_y = in_y; video->in_w = in_w; video->in_h = in_h; if(!result) result = mpeg3video_seek(video); if(!result) result = mpeg3video_read_frame_backend(video, 0); if(video->output_src) mpeg3video_present_frame(video); video->want_yvu = 0; video->byte_seek = -1; return result; } int mpeg3video_read_yuvframe_ptr(mpeg3video_t *video, long frame_number, char **y_output, char **u_output, char **v_output) { int result = 0; video->want_yvu = 1; //printf("mpeg3video_read_yuvframe_ptr 1\n"); // Only decode if it's a different frame if(video->frame_seek < 0 || video->last_number < 0 || video->frame_seek != video->last_number) { //printf("mpeg3video_read_yuvframe_ptr 1 %d\n", video->framenum); if(!result) result = mpeg3video_seek(video); if(!result) result = mpeg3video_read_frame_backend(video, 0); } else { video->framenum = video->frame_seek + 1; video->last_number = video->frame_seek; video->frame_seek = -1; } //printf("mpeg3video_read_yuvframe_ptr 10\n"); if(video->output_src) { *y_output = video->output_src[0]; *u_output = video->output_src[1]; *v_output = video->output_src[2]; } else { *y_output = *u_output = *v_output = 0; } //printf("mpeg3video_read_yuvframe_ptr 20\n"); video->want_yvu = 0; video->byte_seek = -1; //printf("mpeg3video_read_yuvframe_ptr 100\n"); return result; } int mpeg3video_colormodel(mpeg3video_t *video) { switch(video->chroma_format) { case CHROMA422: return MPEG3_YUV422P; break; case CHROMA420: return MPEG3_YUV420P; break; } return MPEG3_YUV420P; } void mpeg3video_dump(mpeg3video_t *video) { printf("mpeg3video_dump 1\n"); printf(" *** sequence extension 1\n"); printf("prog_seq=%d\n", video->prog_seq); printf(" *** picture header 1\n"); printf("pict_type=%d field_sequence=%d\n", video->pict_type, video->field_sequence); printf(" *** picture coding extension 1\n"); printf("field_sequence=%d repeatfirst=%d prog_frame=%d pict_struct=%d\n", video->field_sequence, video->repeatfirst, video->prog_frame, video->pict_struct); } libmpeg3-1.5.4/video/mpeg3video.h0000644000175000017500000000024707742725646017006 0ustar enderender00000000000000#ifndef MPEGVIDEO_H #define MPEGVIDEO_H #include "../bitstream.h" #include "../mpeg3private.inc" #include "idct.h" #include "slice.h" #include "../timecode.h" #endif libmpeg3-1.5.4/video/mpeg3videoprotos.h0000644000175000017500000000027607742725646020257 0ustar enderender00000000000000#ifndef MPEG3VIDEOPROTOS_H #define MPEG3VIDEOPROTOS_H void mpeg3video_idct_conversion(short* block); unsigned int mpeg3slice_showbits(mpeg3_slice_buffer_t *slice_buffer, int bits); #endif libmpeg3-1.5.4/video/output.c0000644000175000017500000010731107753007560016265 0ustar enderender00000000000000#include "../libmpeg3.h" #include "mpeg3video.h" #include #define CLIP(x) ((x) >= 0 ? ((x) < 255 ? (x) : 255) : 0) static long long mpeg3_MMX_0 = 0L; static unsigned long mpeg3_MMX_10w[] = {0x00100010, 0x00100010}; /*dd 00010 0010h, 000100010h */ static unsigned long mpeg3_MMX_80w[] = {0x00800080, 0x00800080}; /*dd 00080 0080h, 000800080h */ static unsigned long mpeg3_MMX_00FFw[] = {0x00ff00ff, 0x00ff00ff}; /*dd 000FF 00FFh, 000FF00FFh */ static unsigned short mpeg3_MMX_Ublucoeff[] = {0x81, 0x81, 0x81, 0x81}; /*dd 00081 0081h, 000810081h */ static unsigned short mpeg3_MMX_Vredcoeff[] = {0x66, 0x66, 0x66, 0x66}; /*dd 00066 0066h, 000660066h */ static unsigned short mpeg3_MMX_Ugrncoeff[] = {0xffe8, 0xffe8, 0xffe8, 0xffe8}; /*dd 0FFE7 FFE7h, 0FFE7FFE7h */ static unsigned short mpeg3_MMX_Vgrncoeff[] = {0xffcd, 0xffcd, 0xffcd, 0xffcd}; /*dd 0FFCC FFCCh, 0FFCCFFCCh */ static unsigned short mpeg3_MMX_Ycoeff[] = {0x4a, 0x4a, 0x4a, 0x4a}; /*dd 0004A 004Ah, 0004A004Ah */ static unsigned short mpeg3_MMX_redmask[] = {0xf800, 0xf800, 0xf800, 0xf800}; /*dd 07c00 7c00h, 07c007c00h */ static unsigned short mpeg3_MMX_grnmask[] = {0x7e0, 0x7e0, 0x7e0, 0x7e0}; /*dd 003e0 03e0h, 003e003e0h */ static unsigned char mpeg3_601_to_rgb[256]; /* Algorithm */ /* r = (int)(*y + 1.371 * (*cr - 128)); */ /* g = (int)(*y - 0.698 * (*cr - 128) - 0.336 * (*cb - 128)); */ /* b = (int)(*y + 1.732 * (*cb - 128)); */ #ifdef HAVE_MMX inline void mpeg3video_rgb16_mmx(unsigned char *lum, unsigned char *cr, unsigned char *cb, unsigned char *out, int rows, int cols, int mod) { unsigned short *row1; int x; unsigned char *y; int col1; row1 = (unsigned short *)out; col1 = cols + mod; mod += cols + mod; mod *= 2; y = lum + cols * rows; x = 0; __asm__ __volatile__( ".align 8\n" "1:\n" "movd (%1), %%mm0\n" /* 4 Cb 0 0 0 0 u3 u2 u1 u0 */ "pxor %%mm7, %%mm7\n" "movd (%0), %%mm1\n" /* 4 Cr 0 0 0 0 v3 v2 v1 v0 */ "punpcklbw %%mm7, %%mm0\n" /* 4 W cb 0 u3 0 u2 0 u1 0 u0 */ "punpcklbw %%mm7, %%mm1\n" /* 4 W cr 0 v3 0 v2 0 v1 0 v0 */ "psubw mpeg3_MMX_80w, %%mm0\n" "psubw mpeg3_MMX_80w, %%mm1\n" "movq %%mm0, %%mm2\n" /* Cb 0 u3 0 u2 0 u1 0 u0 */ "movq %%mm1, %%mm3\n" /* Cr */ "pmullw mpeg3_MMX_Ugrncoeff, %%mm2\n" /* Cb2green 0 R3 0 R2 0 R1 0 R0 */ "movq (%2), %%mm6\n" /* L1 l7 L6 L5 L4 L3 L2 L1 L0 */ "pmullw mpeg3_MMX_Ublucoeff, %%mm0\n" /* Cb2blue */ "pand mpeg3_MMX_00FFw, %%mm6\n" /* L1 00 L6 00 L4 00 L2 00 L0 */ "pmullw mpeg3_MMX_Vgrncoeff, %%mm3\n" /* Cr2green */ "movq (%2), %%mm7\n" /* L2 */ "pmullw mpeg3_MMX_Vredcoeff, %%mm1\n" /* Cr2red */ "psrlw $8, %%mm7\n" /* L2 00 L7 00 L5 00 L3 00 L1 */ "pmullw mpeg3_MMX_Ycoeff, %%mm6\n" /* lum1 */ "paddw %%mm3, %%mm2\n" /* Cb2green + Cr2green == green */ "pmullw mpeg3_MMX_Ycoeff, %%mm7\n" /* lum2 */ "movq %%mm6, %%mm4\n" /* lum1 */ "paddw %%mm0, %%mm6\n" /* lum1 +blue 00 B6 00 B4 00 B2 00 B0 */ "movq %%mm4, %%mm5\n" /* lum1 */ "paddw %%mm1, %%mm4\n" /* lum1 +red 00 R6 00 R4 00 R2 00 R0 */ "paddw %%mm2, %%mm5\n" /* lum1 +green 00 G6 00 G4 00 G2 00 G0 */ "psraw $6, %%mm4\n" /* R1 0 .. 64 */ "movq %%mm7, %%mm3\n" /* lum2 00 L7 00 L5 00 L3 00 L1 */ "psraw $6, %%mm5\n" /* G1 - .. + */ "paddw %%mm0, %%mm7\n" /* Lum2 +blue 00 B7 00 B5 00 B3 00 B1 */ "psraw $6, %%mm6\n" /* B1 0 .. 64 */ "packuswb %%mm4, %%mm4\n" /* R1 R1 */ "packuswb %%mm5, %%mm5\n" /* G1 G1 */ "packuswb %%mm6, %%mm6\n" /* B1 B1 */ "punpcklbw %%mm4, %%mm4\n" "punpcklbw %%mm5, %%mm5\n" "pand mpeg3_MMX_redmask, %%mm4\n" "psllw $3, %%mm5\n" /* GREEN 1 */ "punpcklbw %%mm6, %%mm6\n" "pand mpeg3_MMX_grnmask, %%mm5\n" "pand mpeg3_MMX_redmask, %%mm6\n" "por %%mm5, %%mm4\n" /* */ "psrlw $11, %%mm6\n" /* BLUE 1 */ "movq %%mm3, %%mm5\n" /* lum2 */ "paddw %%mm1, %%mm3\n" /* lum2 +red 00 R7 00 R5 00 R3 00 R1 */ "paddw %%mm2, %%mm5\n" /* lum2 +green 00 G7 00 G5 00 G3 00 G1 */ "psraw $6, %%mm3\n" /* R2 */ "por %%mm6, %%mm4\n" /* MM4 */ "psraw $6, %%mm5\n" /* G2 */ "movq (%2, %3), %%mm6\n" /* L3 */ "psraw $6, %%mm7\n" "packuswb %%mm3, %%mm3\n" "packuswb %%mm5, %%mm5\n" "packuswb %%mm7, %%mm7\n" "pand mpeg3_MMX_00FFw, %%mm6\n" /* L3 */ "punpcklbw %%mm3, %%mm3\n" "punpcklbw %%mm5, %%mm5\n" "pmullw mpeg3_MMX_Ycoeff, %%mm6\n" /* lum3 */ "punpcklbw %%mm7, %%mm7\n" "psllw $3, %%mm5\n" /* GREEN 2 */ "pand mpeg3_MMX_redmask, %%mm7\n" "pand mpeg3_MMX_redmask, %%mm3\n" "psrlw $11, %%mm7\n" /* BLUE 2 */ "pand mpeg3_MMX_grnmask, %%mm5\n" "por %%mm7, %%mm3\n" "movq (%2,%3), %%mm7\n" /* L4 */ "por %%mm5, %%mm3\n" /* */ "psrlw $8, %%mm7\n" /* L4 */ "movq %%mm4, %%mm5\n" "punpcklwd %%mm3, %%mm4\n" "pmullw mpeg3_MMX_Ycoeff, %%mm7\n" /* lum4 */ "punpckhwd %%mm3, %%mm5\n" "movq %%mm4, (%4)\n" "movq %%mm5, 8(%4)\n" "movq %%mm6, %%mm4\n" /* Lum3 */ "paddw %%mm0, %%mm6\n" /* Lum3 +blue */ "movq %%mm4, %%mm5\n" /* Lum3 */ "paddw %%mm1, %%mm4\n" /* Lum3 +red */ "paddw %%mm2, %%mm5\n" /* Lum3 +green */ "psraw $6, %%mm4\n" "movq %%mm7, %%mm3\n" /* Lum4 */ "psraw $6, %%mm5\n" "paddw %%mm0, %%mm7\n" /* Lum4 +blue */ "psraw $6, %%mm6\n" /* Lum3 +blue */ "movq %%mm3, %%mm0\n" /* Lum4 */ "packuswb %%mm4, %%mm4\n" "paddw %%mm1, %%mm3\n" /* Lum4 +red */ "packuswb %%mm5, %%mm5\n" "paddw %%mm2, %%mm0\n" /* Lum4 +green */ "packuswb %%mm6, %%mm6\n" "punpcklbw %%mm4, %%mm4\n" "punpcklbw %%mm5, %%mm5\n" "punpcklbw %%mm6, %%mm6\n" "psllw $3, %%mm5\n" /* GREEN 3 */ "pand mpeg3_MMX_redmask, %%mm4\n" "psraw $6, %%mm3\n" /* psr 6 */ "psraw $6, %%mm0\n" "pand mpeg3_MMX_redmask, %%mm6\n" /* BLUE */ "pand mpeg3_MMX_grnmask, %%mm5\n" "psrlw $11, %%mm6\n" /* BLUE 3 */ "por %%mm5, %%mm4\n" "psraw $6, %%mm7\n" "por %%mm6, %%mm4\n" "packuswb %%mm3, %%mm3\n" "packuswb %%mm0, %%mm0\n" "packuswb %%mm7, %%mm7\n" "punpcklbw %%mm3, %%mm3\n" "punpcklbw %%mm0, %%mm0\n" "punpcklbw %%mm7, %%mm7\n" "pand mpeg3_MMX_redmask, %%mm3\n" "pand mpeg3_MMX_redmask, %%mm7\n" /* BLUE */ "psllw $3, %%mm0\n" /* GREEN 4 */ "psrlw $11, %%mm7\n" "pand mpeg3_MMX_grnmask, %%mm0\n" "por %%mm7, %%mm3\n" "addl $8, %6\n" "por %%mm0, %%mm3\n" "movq %%mm4, %%mm5\n" "punpcklwd %%mm3, %%mm4\n" "punpckhwd %%mm3, %%mm5\n" "movq %%mm4, (%4,%5,2)\n" "movq %%mm5, 8(%4,%5,2)\n" "addl $8, %2\n" "addl $4, %0\n" "addl $4, %1\n" "cmpl %3, %6\n" "leal 16(%4), %4\n" "jl 1b\n" "addl %3, %2\n" /* lum += cols */ "addl %7, %4\n" /* row1 += mod */ "movl $0, %6\n" "cmpl %8, %2\n" "jl 1b\n" : : "r" (cr), "r" (cb), "r" (lum), "r" (cols), "r" (row1) , "r" (col1), "m" (x), "m" (mod), "m" (y) ); } static unsigned long long mpeg3_MMX_U_80 = 0x0000008000800000LL; static unsigned long long mpeg3_MMX_V_80 = 0x0000000000800080LL; static long long mpeg3_MMX_U_COEF = 0x00000058ffd30000LL; static long long mpeg3_MMX_V_COEF = 0x00000000ffea006fLL; static long long mpeg3_MMX_601_Y_COEF = 0x0000004800480048LL; static long long mpeg3_MMX_601_Y_DIFF = 0x0000000000000010LL; inline void mpeg3_bgra32_mmx(unsigned long y, unsigned long u, unsigned long v, unsigned long *output) { asm( /* Output will be 0x00rrggbb with the 00 trailing so this can also be used */ /* for bgr24. */ "movd (%0), %%mm0;\n" /* Load y 0x00000000000000yy */ "movd (%1), %%mm1;\n" /* Load u 0x00000000000000cr */ "movq %%mm0, %%mm3;\n" /* Copy y to temp */ "psllq $16, %%mm1;\n" /* Shift u 0x0000000000cr0000 */ "movd (%2), %%mm2;\n" /* Load v 0x00000000000000cb */ "psllq $16, %%mm3;\n" /* Shift y */ "movq %%mm1, %%mm4;\n" /* Copy u to temp */ "por %%mm3, %%mm0;\n" /* Overlay new y byte 0x0000000000yy00yy */ "psllq $16, %%mm4;\n" /* Shift u */ "movq %%mm2, %%mm5;\n" /* Copy v to temp */ "psllq $16, %%mm3;\n" /* Shift y */ "por %%mm4, %%mm1;\n" /* Overlay new u byte 0x000000cr00cr0000 */ "psllq $16, %%mm5;\n" /* Shift v */ "por %%mm3, %%mm0;\n" /* Overlay new y byte 0x000000yy00yy00yy */ "por %%mm5, %%mm2;\n" /* Overlay new v byte 0x0000000000cb00cb */ /* mm0: 0x000000yy00yy00yy mm1: 0x000000uu00uu0000 mm2: 0x0000000000vv00vv */ "psubw mpeg3_MMX_U_80, %%mm1;\n" /* Subtract 128 from u 0x000000uu00uu0000 */ "pmullw mpeg3_MMX_U_COEF, %%mm1;\n" /* Multiply u coeffs 0x0000uuuuuuuu0000 */ "psllw $6, %%mm0;\n" /* Shift y coeffs 0x0000yyy0yyy0yyy0 */ "psubw mpeg3_MMX_V_80, %%mm2;\n" /* Subtract 128 from v 0x0000000000cb00cb */ "pmullw mpeg3_MMX_V_COEF, %%mm2;\n" /* Multiply v coeffs 0x0000crcrcrcrcrcr */ /* mm0: 0x000000yy00yy00yy mm1: 0x0000uuuuuuuu0000 mm2: 0x00000000vvvvvvvv */ "paddsw %%mm1, %%mm0;\n" /* Add u to result */ "paddsw %%mm2, %%mm0;\n" /* Add v to result 0x0000rrrrggggbbbb */ "psraw $6, %%mm0;\n" /* Demote precision */ "packuswb %%mm0, %%mm0;\n" /* Pack into ARGB 0x0000000000rrggbb */ "movd %%mm0, (%3);\n" /* Store output */ : : "r" (&y), "r" (&u), "r" (&v), "r" (output)); } inline void mpeg3_601_bgra32_mmx(unsigned long y, unsigned long u, unsigned long v, unsigned long *output) { asm( /* Output will be 0x00rrggbb with the 00 trailing so this can also be used */ /* for bgr24. */ "movd (%0), %%mm0;\n" /* Load y 0x00000000000000yy */ "psubsw mpeg3_MMX_601_Y_DIFF, %%mm0;\n" /* Subtract 16 from y */ "movd (%1), %%mm1;\n" /* Load u 0x00000000000000cr */ "movq %%mm0, %%mm3;\n" /* Copy y to temp */ "psllq $16, %%mm1;\n" /* Shift u 0x0000000000cr0000 */ "movd (%2), %%mm2;\n" /* Load v 0x00000000000000cb */ "psllq $16, %%mm3;\n" /* Shift y */ "movq %%mm1, %%mm4;\n" /* Copy u to temp */ "por %%mm3, %%mm0;\n" /* Overlay new y byte 0x0000000000yy00yy */ "psllq $16, %%mm4;\n" /* Shift u */ "movq %%mm2, %%mm5;\n" /* Copy v to temp */ "psllq $16, %%mm3;\n" /* Shift y */ "por %%mm4, %%mm1;\n" /* Overlay new u byte 0x000000cr00cr0000 */ "psllq $16, %%mm5;\n" /* Shift v */ "por %%mm3, %%mm0;\n" /* Overlay new y byte 0x000000yy00yy00yy */ "por %%mm5, %%mm2;\n" /* Overlay new v byte 0x0000000000cb00cb */ /* mm0: 0x000000yy00yy00yy mm1: 0x000000uu00uu0000 mm2: 0x0000000000vv00vv */ "pmullw mpeg3_MMX_601_Y_COEF, %%mm0;\n" /* Scale and shift y coeffs */ "psubw mpeg3_MMX_U_80, %%mm1;\n" /* Subtract 128 from u 0x000000uu00uu0000 */ "pmullw mpeg3_MMX_U_COEF, %%mm1;\n" /* Multiply u coeffs 0x0000uuuuuuuu0000 */ "psubw mpeg3_MMX_V_80, %%mm2;\n" /* Subtract 128 from v 0x0000000000cb00cb */ "pmullw mpeg3_MMX_V_COEF, %%mm2;\n" /* Multiply v coeffs 0x0000crcrcrcrcrcr */ /* mm0: 0x000000yy00yy00yy mm1: 0x0000uuuuuuuu0000 mm2: 0x00000000vvvvvvvv */ "paddsw %%mm1, %%mm0;\n" /* Add u to result */ "paddsw %%mm2, %%mm0;\n" /* Add v to result 0x0000rrrrggggbbbb */ "psraw $6, %%mm0;\n" /* Demote precision */ "packuswb %%mm0, %%mm0;\n" /* Pack into ARGB 0x0000000000rrggbb */ "movd %%mm0, (%3);\n" /* Store output */ : : "r" (&y), "r" (&u), "r" (&v), "r" (output)); } static unsigned long long mpeg3_MMX_U_80_RGB = 0x0000000000800080LL; static unsigned long long mpeg3_MMX_V_80_RGB = 0x0000008000800000LL; static long long mpeg3_MMX_U_COEF_RGB = 0x00000000ffd30058LL; static long long mpeg3_MMX_V_COEF_RGB = 0x0000006fffea0000LL; inline void mpeg3_rgba32_mmx(unsigned long y, unsigned long u, unsigned long v, unsigned long *output) { asm( /* Output will be 0x00bbggrr with the 00 trailing so this can also be used */ /* for rgb24. */ "movd (%0), %%mm0;\n" /* Load y 0x00000000000000yy */ "movd (%1), %%mm1;\n" /* Load v 0x00000000000000vv */ "movq %%mm0, %%mm3;\n" /* Copy y to temp */ "psllq $16, %%mm1;\n" /* Shift v 0x0000000000vv0000 */ "movd (%2), %%mm2;\n" /* Load u 0x00000000000000uu */ "psllq $16, %%mm3;\n" /* Shift y */ "movq %%mm1, %%mm4;\n" /* Copy v to temp */ "por %%mm3, %%mm0;\n" /* Overlay new y byte 0x0000000000yy00yy */ "psllq $16, %%mm4;\n" /* Shift v */ "movq %%mm2, %%mm5;\n" /* Copy u to temp */ "psllq $16, %%mm3;\n" /* Shift y */ "por %%mm4, %%mm1;\n" /* Overlay new v byte 0x000000vv00vv0000 */ "psllq $16, %%mm5;\n" /* Shift u */ "por %%mm3, %%mm0;\n" /* Overlay new y byte 0x000000yy00yy00yy */ "por %%mm5, %%mm2;\n" /* Overlay new u byte 0x0000000000uu00uu */ /* mm0: 0x000000yy00yy00yy mm1: 0x000000vv00vv0000 mm2: 0x0000000000uu00uu */ "psubw mpeg3_MMX_V_80_RGB, %%mm1;\n" /* Subtract 128 from v 0x000000vv00vv0000 */ "pmullw mpeg3_MMX_V_COEF_RGB, %%mm1;\n" /* Multiply v coeffs 0x0000vvvvvvvv0000 */ "psllw $6, %%mm0;\n" /* Shift y coeffs 0x0000yyy0yyy0yyy0 */ "psubw mpeg3_MMX_U_80_RGB, %%mm2;\n" /* Subtract 128 from u 0x0000000000uu00uu */ "pmullw mpeg3_MMX_U_COEF_RGB, %%mm2;\n" /* Multiply u coeffs 0x0000uuuuuuuuuuuu */ /* mm0: 0x000000yy00yy00yy mm1: 0x0000vvvvvvvv0000 mm2: 0x00000000uuuuuuuu */ "paddsw %%mm1, %%mm0;\n" /* Add v to result */ "paddsw %%mm2, %%mm0;\n" /* Add u to result 0x0000bbbbggggrrrr */ "psraw $6, %%mm0;\n" /* Demote precision */ "packuswb %%mm0, %%mm0;\n" /* Pack into RGBA 0x0000000000bbggrr */ "movd %%mm0, (%3);\n" /* Store output */ : : "r" (&y), "r" (&v), "r" (&u), "r" (output)); } inline void mpeg3_601_rgba32_mmx(unsigned long y, unsigned long u, unsigned long v, unsigned long *output) { asm( /* Output will be 0x00bbggrr with the 00 trailing so this can also be used */ /* for rgb24. */ "movd (%0), %%mm0;\n" /* Load y 0x00000000000000yy */ "psubsw mpeg3_MMX_601_Y_DIFF, %%mm0;\n" /* Subtract 16 from y */ "movd (%1), %%mm1;\n" /* Load v 0x00000000000000vv */ "movq %%mm0, %%mm3;\n" /* Copy y to temp */ "psllq $16, %%mm1;\n" /* Shift v 0x0000000000vv0000 */ "movd (%2), %%mm2;\n" /* Load u 0x00000000000000uu */ "psllq $16, %%mm3;\n" /* Shift y */ "movq %%mm1, %%mm4;\n" /* Copy v to temp */ "por %%mm3, %%mm0;\n" /* Overlay new y byte 0x0000000000yy00yy */ "psllq $16, %%mm4;\n" /* Shift v */ "movq %%mm2, %%mm5;\n" /* Copy u to temp */ "psllq $16, %%mm3;\n" /* Shift y */ "por %%mm4, %%mm1;\n" /* Overlay new v byte 0x000000vv00vv0000 */ "psllq $16, %%mm5;\n" /* Shift u */ "por %%mm3, %%mm0;\n" /* Overlay new y byte 0x000000yy00yy00yy */ "por %%mm5, %%mm2;\n" /* Overlay new u byte 0x0000000000uu00uu */ /* mm0: 0x000000yy00yy00yy mm1: 0x000000vv00vv0000 mm2: 0x0000000000uu00uu */ "pmullw mpeg3_MMX_601_Y_COEF, %%mm0;\n" /* Scale y coeffs */ "psubw mpeg3_MMX_V_80_RGB, %%mm1;\n" /* Subtract 128 from v 0x000000vv00vv0000 */ "pmullw mpeg3_MMX_V_COEF_RGB, %%mm1;\n" /* Multiply v coeffs 0x0000vvvvvvvv0000 */ "psubw mpeg3_MMX_U_80_RGB, %%mm2;\n" /* Subtract 128 from u 0x0000000000uu00uu */ "pmullw mpeg3_MMX_U_COEF_RGB, %%mm2;\n" /* Multiply u coeffs 0x0000uuuuuuuuuuuu */ /* mm0: 0x000000yy00yy00yy mm1: 0x0000vvvvvvvv0000 mm2: 0x00000000uuuuuuuu */ "paddsw %%mm1, %%mm0;\n" /* Add v to result */ "paddsw %%mm2, %%mm0;\n" /* Add u to result 0x0000bbbbggggrrrr */ "psraw $6, %%mm0;\n" /* Demote precision */ "packuswb %%mm0, %%mm0;\n" /* Pack into RGBA 0x0000000000bbggrr */ "movd %%mm0, (%3);\n" /* Store output */ : : "r" (&y), "r" (&v), "r" (&u), "r" (output)); } #endif #define DITHER_ROW_HEAD \ for(h = 0; h < video->out_h; h++) \ { \ y_in = &src[0][(video->y_table[h] + video->in_y) * \ video->coded_picture_width] + \ video->in_x; \ if(video->chroma_format == CHROMA420) \ { \ cb_in = &src[1][((video->y_table[h] + video->in_y) >> 1) * \ video->chrom_width] + \ (video->in_x >> 1); \ cr_in = &src[2][((video->y_table[h] + video->in_y) >> 1) * \ video->chrom_width] + \ (video->in_x >> 1); \ } \ else \ { \ cb_in = &src[1][(video->y_table[h] + video->in_y) * \ video->chrom_width] + \ (video->in_x >> 1); \ cr_in = &src[2][(video->y_table[h] + video->in_y) * \ video->chrom_width] + \ (video->in_x >> 1); \ } \ data = output_rows[h]; #define DITHER_ROW_TAIL \ } #define DITHER_SCALE_HEAD \ for(w = 0; w < video->out_w; w++) \ { \ uv_subscript = video->x_table[w] / 2; \ y_l = y_in[video->x_table[w]]; \ y_l <<= 16; \ r_l = (y_l + video->cr_to_r[cr_in[uv_subscript]]) >> 16; \ g_l = (y_l + video->cr_to_g[cr_in[uv_subscript]] + video->cb_to_g[cb_in[uv_subscript]]) >> 16; \ b_l = (y_l + video->cb_to_b[cb_in[uv_subscript]]) >> 16; #define DITHER_SCALE_601_HEAD \ for(w = 0; w < video->out_w; w++) \ { \ uv_subscript = video->x_table[w] / 2; \ y_l = mpeg3_601_to_rgb[y_in[video->x_table[w]]]; \ y_l <<= 16; \ r_l = (y_l + video->cr_to_r[cr_in[uv_subscript]]) >> 16; \ g_l = (y_l + video->cr_to_g[cr_in[uv_subscript]] + video->cb_to_g[cb_in[uv_subscript]]) >> 16; \ b_l = (y_l + video->cb_to_b[cb_in[uv_subscript]]) >> 16; #define DITHER_SCALE_TAIL \ } #define DITHER_MMX_SCALE_HEAD \ for(w = 0; w < video->out_w; w++) \ { \ uv_subscript = video->x_table[w] / 2; #define DITHER_MMX_SCALE_TAIL \ data += step; \ } #define DITHER_MMX_HEAD \ for(w = 0; w < video->out_w; w += 2) \ { #define DITHER_MMX_TAIL \ data += step; \ cr_in++; \ cb_in++; \ } #define DITHER_HEAD \ for(w = 0; w < video->horizontal_size; w++) \ { \ y_l = *y_in++; \ y_l <<= 16; \ r_l = (y_l + video->cr_to_r[*cr_in]) >> 16; \ g_l = (y_l + video->cr_to_g[*cr_in] + video->cb_to_g[*cb_in]) >> 16; \ b_l = (y_l + video->cb_to_b[*cb_in]) >> 16; #define DITHER_601_HEAD \ for(w = 0; w < video->horizontal_size; w++) \ { \ y_l = mpeg3_601_to_rgb[*y_in++]; \ y_l <<= 16; \ r_l = (y_l + video->cr_to_r[*cr_in]) >> 16; \ g_l = (y_l + video->cr_to_g[*cr_in] + video->cb_to_g[*cb_in]) >> 16; \ b_l = (y_l + video->cb_to_b[*cb_in]) >> 16; #define DITHER_TAIL \ if(w & 1) \ { \ cr_in++; \ cb_in++; \ } \ } #define STORE_PIXEL_BGR888 \ *data++ = CLIP(b_l); \ *data++ = CLIP(g_l); \ *data++ = CLIP(r_l); #define STORE_PIXEL_BGRA8888 \ *data++ = CLIP(b_l); \ *data++ = CLIP(g_l); \ *data++ = CLIP(r_l); \ *data++ = 0; #define STORE_PIXEL_RGB565 \ *((unsigned short*)data)++ = \ ((CLIP(r_l) & 0xf8) << 8) | \ ((CLIP(g_l) & 0xfc) << 3) | \ ((CLIP(b_l) & 0xf8) >> 3); #define STORE_PIXEL_RGB888 \ *data++ = CLIP(r_l); \ *data++ = CLIP(g_l); \ *data++ = CLIP(b_l); #define STORE_PIXEL_RGBA8888 \ *data++ = CLIP(r_l); \ *data++ = CLIP(g_l); \ *data++ = CLIP(b_l); \ *data++ = 0; #define STORE_PIXEL_RGBA16161616 \ *data_s++ = CLIP(r_l); \ *data_s++ = CLIP(g_l); \ *data_s++ = CLIP(b_l); \ *data_s++ = 0; /* Only good for YUV 4:2:0 */ int mpeg3video_ditherframe(mpeg3video_t *video, unsigned char **src, unsigned char **output_rows) { int h = 0; register unsigned char *y_in, *cb_in, *cr_in; long y_l, r_l, b_l, g_l; register unsigned char *data; register int uv_subscript, step, w = -1; #ifdef HAVE_MMX /* =================================== MMX ===================================== */ if(video->have_mmx && video->out_w == video->horizontal_size && video->out_h == video->vertical_size && video->in_w == video->out_w && video->in_h == video->out_h && video->in_x == 0 && video->in_y == 0 && (video->color_model == MPEG3_RGB565 || video->color_model == MPEG3_601_RGB565) && video->chroma_format == CHROMA420) { /* Unscaled 16 bit from NIST */ mpeg3video_rgb16_mmx(src[0], src[2], src[1], output_rows[0], video->out_h, video->out_w, (output_rows[1] - output_rows[0]) / 2 - video->out_w); } else if(video->have_mmx && (video->color_model == MPEG3_BGRA8888 || video->color_model == MPEG3_BGR888 || /* video->color_model == MPEG3_RGB888 || */ video->color_model == MPEG3_RGBA8888 || video->color_model == MPEG3_601_BGR888 || video->color_model == MPEG3_601_BGRA8888 || video->color_model == MPEG3_601_RGB888 || video->color_model == MPEG3_601_RGBA8888)) { /* Original MMX */ if(video->color_model == MPEG3_BGRA8888 || video->color_model == MPEG3_RGBA8888 || video->color_model == MPEG3_601_BGRA8888 || video->color_model == MPEG3_601_RGBA8888) step = 4; else if(video->color_model == MPEG3_BGR888 || video->color_model == MPEG3_RGB888 || video->color_model == MPEG3_601_BGR888 || video->color_model == MPEG3_601_RGB888) step = 3; DITHER_ROW_HEAD /* Transfer row with scaling */ if(video->out_w != video->horizontal_size) { switch(video->color_model) { case MPEG3_BGRA8888: case MPEG3_BGR888: DITHER_MMX_SCALE_HEAD mpeg3_bgra32_mmx(y_in[video->x_table[w]], cr_in[uv_subscript], cb_in[uv_subscript], (unsigned long*)data); DITHER_MMX_SCALE_TAIL break; case MPEG3_601_BGRA8888: case MPEG3_601_BGR888: DITHER_MMX_SCALE_HEAD mpeg3_601_bgra32_mmx(y_in[video->x_table[w]], cr_in[uv_subscript], cb_in[uv_subscript], (unsigned long*)data); DITHER_MMX_SCALE_TAIL break; case MPEG3_RGBA8888: case MPEG3_RGB888: DITHER_MMX_SCALE_HEAD mpeg3_rgba32_mmx(y_in[video->x_table[w]], cr_in[uv_subscript], cb_in[uv_subscript], (unsigned long*)data); DITHER_MMX_SCALE_TAIL break; case MPEG3_601_RGBA8888: case MPEG3_601_RGB888: DITHER_MMX_SCALE_HEAD mpeg3_601_rgba32_mmx(y_in[video->x_table[w]], cr_in[uv_subscript], cb_in[uv_subscript], (unsigned long*)data); DITHER_MMX_SCALE_TAIL break; } } else /* Transfer row unscaled */ { switch(video->color_model) { /* MMX byte swap 24 and 32 bit */ case MPEG3_BGRA8888: case MPEG3_BGR888: DITHER_MMX_HEAD mpeg3_bgra32_mmx(*y_in++, *cr_in, *cb_in, (unsigned long*)data); data += step; mpeg3_bgra32_mmx(*y_in++, *cr_in, *cb_in, (unsigned long*)data); DITHER_MMX_TAIL break; /* MMX 601 byte swap 24 and 32 bit */ case MPEG3_601_BGRA8888: case MPEG3_601_BGR888: DITHER_MMX_HEAD mpeg3_601_bgra32_mmx(*y_in++, *cr_in, *cb_in, (unsigned long*)data); data += step; mpeg3_601_bgra32_mmx(*y_in++, *cr_in, *cb_in, (unsigned long*)data); DITHER_MMX_TAIL break; /* MMX 24 and 32 bit no byte swap */ case MPEG3_RGBA8888: case MPEG3_RGB888: DITHER_MMX_HEAD mpeg3_rgba32_mmx(*y_in++, *cr_in, *cb_in, (unsigned long*)data); data += step; mpeg3_rgba32_mmx(*y_in++, *cr_in, *cb_in, (unsigned long*)data); DITHER_MMX_TAIL break; /* MMX 601 24 and 32 bit no byte swap */ case MPEG3_601_RGBA8888: case MPEG3_601_RGB888: DITHER_MMX_HEAD mpeg3_601_rgba32_mmx(*y_in++, *cr_in, *cb_in, (unsigned long*)data); data += step; mpeg3_601_rgba32_mmx(*y_in++, *cr_in, *cb_in, (unsigned long*)data); DITHER_MMX_TAIL break; } } DITHER_ROW_TAIL } else #endif /* ================================== NO MMX ==================================== */ { DITHER_ROW_HEAD /* Transfer row with scaling */ if(video->out_w != video->horizontal_size) { switch(video->color_model) { case MPEG3_BGR888: DITHER_SCALE_HEAD STORE_PIXEL_BGR888 DITHER_SCALE_TAIL break; case MPEG3_BGRA8888: DITHER_SCALE_HEAD STORE_PIXEL_BGRA8888 DITHER_SCALE_TAIL break; case MPEG3_RGB565: DITHER_SCALE_HEAD STORE_PIXEL_RGB565 DITHER_SCALE_TAIL break; case MPEG3_RGB888: DITHER_SCALE_HEAD STORE_PIXEL_RGB888 DITHER_SCALE_TAIL break; case MPEG3_RGBA8888: DITHER_SCALE_HEAD STORE_PIXEL_RGBA8888 DITHER_SCALE_TAIL break; case MPEG3_601_BGR888: DITHER_SCALE_601_HEAD STORE_PIXEL_BGR888 DITHER_SCALE_TAIL break; case MPEG3_601_BGRA8888: DITHER_SCALE_601_HEAD STORE_PIXEL_BGRA8888 DITHER_SCALE_TAIL break; case MPEG3_601_RGB565: DITHER_SCALE_601_HEAD STORE_PIXEL_RGB565 DITHER_SCALE_TAIL break; case MPEG3_601_RGB888: DITHER_SCALE_601_HEAD STORE_PIXEL_RGB888 DITHER_SCALE_TAIL break; case MPEG3_601_RGBA8888: DITHER_SCALE_601_HEAD STORE_PIXEL_RGBA8888 DITHER_SCALE_TAIL break; case MPEG3_RGBA16161616: { register unsigned short *data_s = (unsigned short*)data; DITHER_SCALE_HEAD STORE_PIXEL_RGBA16161616 DITHER_SCALE_TAIL } break; } } else { /* Transfer row unscaled */ switch(video->color_model) { case MPEG3_BGR888: DITHER_HEAD STORE_PIXEL_BGR888 DITHER_TAIL break; case MPEG3_BGRA8888: DITHER_HEAD STORE_PIXEL_BGRA8888 DITHER_TAIL break; case MPEG3_RGB565: DITHER_HEAD STORE_PIXEL_RGB565 DITHER_TAIL break; case MPEG3_RGB888: DITHER_HEAD STORE_PIXEL_RGB888 DITHER_TAIL break; case MPEG3_RGBA8888: DITHER_HEAD STORE_PIXEL_RGBA8888 DITHER_TAIL break; case MPEG3_601_BGR888: DITHER_601_HEAD STORE_PIXEL_BGR888 DITHER_TAIL break; case MPEG3_601_BGRA8888: DITHER_601_HEAD STORE_PIXEL_BGRA8888 DITHER_TAIL break; case MPEG3_601_RGB565: DITHER_601_HEAD STORE_PIXEL_RGB565 DITHER_TAIL break; case MPEG3_601_RGB888: DITHER_601_HEAD STORE_PIXEL_RGB888 DITHER_TAIL break; case MPEG3_601_RGBA8888: DITHER_601_HEAD STORE_PIXEL_RGBA8888 DITHER_TAIL break; case MPEG3_RGBA16161616: { register unsigned short *data_s = (unsigned short*)data; DITHER_HEAD STORE_PIXEL_RGBA16161616 DITHER_TAIL } break; } } DITHER_ROW_TAIL } /* End of non-MMX */ #ifdef HAVE_MMX if(video->have_mmx) __asm__ __volatile__ ("emms"); #endif return 0; } int mpeg3video_ditherframe444(mpeg3video_t *video, unsigned char *src[]) { return 0; } int mpeg3video_dithertop(mpeg3video_t *video, unsigned char *src[]) { return mpeg3video_ditherframe(video, src, video->output_rows); } int mpeg3video_dithertop444(mpeg3video_t *video, unsigned char *src[]) { return 0; } int mpeg3video_ditherbot(mpeg3video_t *video, unsigned char *src[]) { return 0; } int mpeg3video_ditherbot444(mpeg3video_t *video, unsigned char *src[]) { return 0; } void memcpy_fast(unsigned char *output, unsigned char *input, long len) { int i, len2; /* 8 byte alignment */ /* * if(!((long)input & 0x7)) * { * len2 = len >> 4; * for(i = 0; i < len2; ) * { * ((int64_t*)output)[i] = ((int64_t*)input)[i]; * i++; * ((int64_t*)output)[i] = ((int64_t*)input)[i]; * i++; * } * * for(i *= 16; i < len; i++) * { * output[i] = input[i]; * } * } * else */ memcpy(output, input, len); } int mpeg3video_init_output() { int i, value; for(i = 0; i < 256; i++) { value = (int)(1.1644 * i - 255 * 0.0627 + 0.5); if(value < 0) value = 0; else if(value > 255) value = 255; mpeg3_601_to_rgb[i] = value; } return 0; } int mpeg3video_present_frame(mpeg3video_t *video) { int i, j, k, l; unsigned char **src = video->output_src; /* Copy YUV buffers */ if(video->want_yvu) { long size0, size1; long offset0, offset1; int chroma_denominator; if(video->chroma_format == CHROMA420) chroma_denominator = 2; else chroma_denominator = 1; /* Drop a frame */ if(!video->y_output) return 0; /* Copy a frame */ /* Three blocks */ if(video->in_x == 0 && video->in_w >= video->coded_picture_width && video->row_span == video->coded_picture_width) { size0 = video->coded_picture_width * video->in_h; size1 = video->chrom_width * (int)((float)video->in_h / chroma_denominator + 0.5); offset0 = video->coded_picture_width * video->in_y; offset1 = video->chrom_width * (int)((float)video->in_y / chroma_denominator + 0.5); printf("mpeg3video_present_frame 1\n"); /* * if(video->in_y > 0) * { * offset[1] += video->chrom_width / 2; * size[1] += video->chrom_width / 2; * } */ memcpy(video->y_output, src[0] + offset0, size0); memcpy(video->u_output, src[1] + offset1, size1); memcpy(video->v_output, src[2] + offset1, size1); } else /* One block per row */ { //printf("mpeg3video_present_frame 2 %d %d %d\n", video->in_w, video->coded_picture_width, video->chrom_width); int row_span = video->in_w; int row_span0; int row_span1; if(video->row_span) row_span = video->row_span; row_span0 = row_span; row_span1 = (row_span >> 1); size0 = video->in_w; size1 = (video->in_w >> 1); offset0 = video->coded_picture_width * video->in_y; offset1 = video->chrom_width * video->in_y / chroma_denominator; for(i = 0; i < video->in_h; i++) { memcpy(video->y_output + i * row_span0, src[0] + offset0 + video->in_x, size0); offset0 += video->coded_picture_width; if(chroma_denominator == 1 || !(i % 2)) { memcpy(video->u_output + i / chroma_denominator * row_span1, src[1] + offset1 + (video->in_x >> 1), size1); memcpy(video->v_output + i / chroma_denominator * row_span1, src[2] + offset1 + (video->in_x >> 1), size1); if(video->horizontal_size < video->in_w) { memset(video->u_output + i / chroma_denominator * row_span1 + (video->horizontal_size >> 1), 0x80, (video->in_w >> 1) - (video->horizontal_size >> 1)); memset(video->v_output + i / chroma_denominator * row_span1 + (video->horizontal_size >> 1), 0x80, (video->in_w >> 1) - (video->horizontal_size >> 1)); } } if(chroma_denominator == 1 || (i % 2)) offset1 += video->chrom_width; } } return 0; } /* Want RGB buffer */ /* Copy the frame to the output with YUV to RGB conversion */ if(video->prog_seq) { if(video->chroma_format != CHROMA444) { mpeg3video_ditherframe(video, src, video->output_rows); } else mpeg3video_ditherframe444(video, src); } else { if((video->pict_struct == FRAME_PICTURE && video->topfirst) || video->pict_struct == BOTTOM_FIELD) { /* top field first */ if(video->chroma_format != CHROMA444) { mpeg3video_dithertop(video, src); mpeg3video_ditherbot(video, src); } else { mpeg3video_dithertop444(video, src); mpeg3video_ditherbot444(video, src); } } else { /* bottom field first */ if(video->chroma_format != CHROMA444) { mpeg3video_ditherbot(video, src); mpeg3video_dithertop(video, src); } else { mpeg3video_ditherbot444(video, src); mpeg3video_dithertop444(video, src); } } } return 0; } int mpeg3video_display_second_field(mpeg3video_t *video) { /* Not used */ return 0; } libmpeg3-1.5.4/video/reconmmx.s0000644000175000017500000001460707742725646016614 0ustar enderender00000000000000ADD_1: dd 01010101h, 01010101h MASK_AND: dd 7f7f7f7fh, 7f7f7f7fh PLUS_384: dd 01800180h, 01800180h PLUS_128: dd 00800080h, 00800080h %assign LocalFrameSize 0 %assign RegisterStorageSize 16 ; Arguments: %assign source LocalFrameSize + RegisterStorageSize + 4 %assign dest LocalFrameSize + RegisterStorageSize + 8 %assign lx2 LocalFrameSize + RegisterStorageSize + 12 %assign h LocalFrameSize + RegisterStorageSize + 16 ; Locals (on local stack frame) ; extern void C rec_mmx ( ; unsigned char *source, ; unsigned char *dest, ; int lx2, ; int h ; ; The local variables are on the stack, ; global recva_mmx global recvac_mmx global rech_mmx global rechc_mmx global add_block_mmx global set_block_mmx align 16 rech_mmx: push esi push edi push ecx push ebx mov esi, [esp+source] mov edi, [esp+dest] mov ecx, [esp+h] mov ebx, [esp+lx2] movq mm5, [MASK_AND] movq mm6, [ADD_1] .rech1: movq mm0,[esi] movq mm1,[esi+1] movq mm2,[esi+8] movq mm3,[esi+9] psrlw mm0,1 psrlw mm1,1 psrlw mm2,1 psrlw mm3,1 pand mm0,mm5 pand mm1,mm5 pand mm2,mm5 pand mm3,mm5 paddusb mm0,mm1 paddusb mm2,mm3 paddusb mm0,mm6 paddusb mm2,mm6 movq [edi],mm0 add esi,ebx movq [edi+8],mm2 add edi,ebx dec ecx jnz .rech1 emms pop ebx pop ecx pop edi pop esi ret align 16 rechc_mmx: push esi push edi push ecx push ebx ; sub esp, LocalFrameSize mov esi, [esp+source] mov edi, [esp+dest] mov ecx, [esp+h] mov ebx, [esp+lx2] movq mm5, [MASK_AND] movq mm6, [ADD_1] .rechc1: movq mm0,[esi] movq mm1,[esi+1] psrlw mm0,1 psrlw mm1,1 pand mm0,mm5 pand mm1,mm5 paddusb mm0,mm1 paddusb mm0,mm6 movq [edi],mm0 add edi,ebx add esi,ebx dec ecx jnz .rechc1 emms ; add esp, LocalFrameSize pop ebx pop ecx pop edi pop esi ret %assign RegisterStorageSize 20 %assign source LocalFrameSize + RegisterStorageSize + 4 %assign dest LocalFrameSize + RegisterStorageSize + 8 %assign lx LocalFrameSize + RegisterStorageSize + 12 %assign lx2 LocalFrameSize + RegisterStorageSize + 16 %assign h LocalFrameSize + RegisterStorageSize + 20 align 16 recva_mmx: push esi push edi push ecx push ebx push edx mov esi, [esp+source] mov edi, [esp+dest] mov ecx, [esp+h] mov ebx, [esp+lx2] mov edx, [esp+lx] movq mm7, [MASK_AND] movq mm6, [ADD_1] .recva1: movq mm0,[esi] movq mm1,[esi+edx] movq mm2,[esi+8] movq mm3,[esi+edx+8] movq mm4,[edi] movq mm5,[edi+8] psrlw mm0,1 psrlw mm1,1 psrlw mm2,1 psrlw mm3,1 psrlw mm4,1 psrlw mm5,1 pand mm0,mm7 pand mm1,mm7 pand mm2,mm7 pand mm3,mm7 pand mm4,mm7 pand mm5,mm7 paddusb mm0,mm1 paddusb mm2,mm3 paddusb mm0,mm6 paddusb mm2,mm6 psrlw mm0,1 psrlw mm2,1 pand mm0,mm7 pand mm2,mm7 paddusb mm4,mm0 paddusb mm5,mm2 paddusb mm4,mm6 paddusb mm5,mm6 movq [edi],mm4 movq [edi+8],mm5 add edi,ebx add esi,ebx dec ecx jnz near .recva1 emms pop edx pop ebx pop ecx pop edi pop esi ret align 16 recvac_mmx: push esi push edi push ecx push ebx push edx mov esi, [esp+source] mov edi, [esp+dest] mov ecx, [esp+h] mov ebx, [esp+lx2] mov edx, [esp+lx] movq mm5, [MASK_AND] movq mm6, [ADD_1] .recvac1: movq mm0,[esi] movq mm1,[esi+edx] movq mm4,[edi] psrlw mm0,1 psrlw mm1,1 psrlw mm4,1 pand mm0,mm5 pand mm1,mm5 pand mm4,mm5 paddusb mm0,mm1 paddusb mm0,mm6 psrlw mm0,1 pand mm0,mm5 paddusb mm4,mm0 paddusb mm4,mm6 movq [edi],mm4 add edi,ebx add esi,ebx dec ecx jnz .recvac1 emms pop edx pop ebx pop ecx pop edi pop esi ret %assign RegisterStorageSize 20 %assign rfp LocalFrameSize + RegisterStorageSize + 4 %assign bp LocalFrameSize + RegisterStorageSize + 8 %assign iincr LocalFrameSize + RegisterStorageSize + 12 ; FIXME clipping needs to be done align 16 add_block_mmx: push esi push edi push ecx push ebx push edx mov esi, [esp+bp] mov edi, [esp+rfp] mov ebx, [esp+iincr] ; movq mm7, [PLUS_384] mov ecx,8 pxor mm2,mm2 ; clear %rep 8 movq mm0, [edi] ; get dest movq mm1,mm0 punpcklbw mm0,mm2 punpckhbw mm1,mm2 paddsw mm0, [esi] paddsw mm1, [esi+8] ; paddsw mm0, mm7 ; paddsw mm1, mm7 packuswb mm0,mm1 movq [edi], mm0 add edi,ebx add esi,16 %endrep emms pop edx pop ebx pop ecx pop edi pop esi ret align 16 set_block_mmx: push esi push edi push ecx push ebx push edx mov esi, [esp+bp] mov edi, [esp+rfp] mov ebx, [esp+iincr] movq mm7, [PLUS_128] %rep 4 movq mm0, [esi] movq mm1, [esi+8] paddsw mm0, mm7 movq mm2, [esi+16] paddsw mm1, mm7 movq mm3, [esi+24] paddsw mm2, mm7 packuswb mm0, mm1 paddsw mm3, mm7 movq [edi], mm0 packuswb mm2, mm3 add edi, ebx add esi, 32 movq [edi], mm2 add edi, ebx %endrep emms pop edx pop ebx pop ecx pop edi pop esi ret libmpeg3-1.5.4/video/reconstruct.c0000644000175000017500000011351307742725646017313 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include #ifdef HAVE_MMX #ifdef HAVE_3Dnow static inline void recva_mmx(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { __asm__( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq 8(%1), %%mm1\n" /* 8 s */ "movq (%4), %%mm2\n" /* 8 s +lx */ "movq 8(%4), %%mm3\n" /* 8 s +lx **/ "pavgusb %%mm2, %%mm0\n" "addl %3, %1\n" "pavgusb %%mm3, %%mm1\n" "movq (%2), %%mm2\n" /* 8 d */ "movq 8(%2), %%mm3\n" /* 8 d */ "pavgusb %%mm2, %%mm0\n" "addl %3, %4\n" "pavgusb %%mm3, %%mm1\n" "movq %%mm0, (%2)\n" "movq %%mm1, 8(%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); } static inline void recvac_mmx(unsigned char *s, unsigned char *d, int lx,int lx2, int h) { __asm__( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq (%4), %%mm2\n" /* 8 s +lx */ "addl %3, %1\n" "pavgusb %%mm2, %%mm0\n" "movq (%2), %%mm3\n" /* 8 d */ "addl %3, %4\n" "pavgusb %%mm3, %%mm0\n" "movq %%mm0, (%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); } static inline void rech_mmx(unsigned char *s, unsigned char *d, int lx2, int h) { __asm__ ( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq 8(%1), %%mm1\n" /* 8 s */ "movq 1(%1), %%mm2\n" /* 8 s */ "movq 9(%1), %%mm3\n" /* 8 s */ "pavgusb %%mm2, %%mm0\n" "addl %3, %1\n" "pavgusb %%mm3, %%mm1\n" "movq %%mm0, (%2)\n" "movq %%mm1, 8(%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); } static inline void rechc_mmx(unsigned char *s, unsigned char *d, int lx2, int h) { __asm__ ( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq 1(%1), %%mm2\n" /* 8 s +1 */ "addl %3, %1\n" "pavgusb %%mm2, %%mm0\n" "movq %%mm0, (%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); } static inline void recha_mmx(unsigned char *s, unsigned char *d,int lx2, int h) { __asm__ ( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq 8(%1), %%mm1\n" /* 8 s */ "movq 1(%1), %%mm2\n" /* 8 s */ "movq 9(%1), %%mm3\n" /* 8 s */ "pavgusb %%mm2, %%mm0\n" "addl %3, %1\n" "pavgusb %%mm3, %%mm1\n" "movq (%2), %%mm2\n" /* 8 d */ "movq 8(%2), %%mm3\n" /* 8 d */ "pavgusb %%mm2, %%mm0\n" "pavgusb %%mm3, %%mm1\n" "movq %%mm0, (%2)\n" "movq %%mm1, 8(%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); } static inline void rechac_mmx(unsigned char *s,unsigned char *d, int lx2, int h) { __asm__ ( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq 1(%1), %%mm2\n" /* 8 s */ "addl %3, %1\n" "pavgusb %%mm2, %%mm0\n" "movq (%2), %%mm1\n" /* 8 d */ "pavgusb %%mm1, %%mm0\n" "movq %%mm0, (%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); } static inline void rec4_mmx(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { __asm__ __volatile__( "movq (%1), %%mm0\n" /* 8 s */ "movq 8(%1), %%mm1\n" /* 8 s */ "movq 1(%1), %%mm2\n" /* 8 s +1*/ "movq 9(%1), %%mm3\n" /* 8 s +1*/ ".align 8\n" "1:" "movq (%4), %%mm4\n" /* 8 s+lx */ "pavgusb %%mm2, %%mm0\n" "movq 8(%4), %%mm5\n" /* 8 s+lx */ "pavgusb %%mm3, %%mm1\n" "movq 1(%4), %%mm6\n" /* 8 s+lx +1*/ "pavgusb %%mm4, %%mm0\n" "movq 9(%4), %%mm7\n" /* 8 s+lx +1*/ "pavgusb %%mm5, %%mm1\n" "pavgusb %%mm6, %%mm0\n" "addl %3, %4\n" "pavgusb %%mm7, %%mm1\n" "movq %%mm0, (%2)\n" "movq %%mm6, %%mm2\n" "movq %%mm7, %%mm3\n" "movq %%mm1, 8(%2)\n" "movq %%mm4, %%mm0\n" "movq %%mm5, %%mm1\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); } static inline void rec4c_mmx(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { __asm__ __volatile__( "movq (%1), %%mm0\n" /* 8 s */ "movq 1(%1), %%mm2\n" /* 8 s +1*/ ".align 8\n" "1:" "movq (%4), %%mm4\n" /* 8 s+lx */ "pavgusb %%mm2, %%mm0\n" "movq 1(%4), %%mm6\n" /* 8 s+lx +1*/ "pavgusb %%mm4, %%mm0\n" "addl %3, %4\n" "pavgusb %%mm6, %%mm0\n" "movq %%mm0, (%2)\n" "movq %%mm6, %%mm2\n" "movq %%mm4, %%mm0\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); } static inline void rec4a_mmx(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { __asm__ __volatile__( "movq (%1), %%mm0\n" /* 8 s */ "movq 8(%1), %%mm1\n" /* 8 s */ "movq 1(%1), %%mm2\n" /* 8 s +1*/ "movq 9(%1), %%mm3\n" /* 8 s +1*/ ".align 8\n" "1:" "movq (%4), %%mm4\n" /* 8 s+lx */ "pavgusb %%mm2, %%mm0\n" "movq 8(%4), %%mm5\n" /* 8 s+lx */ "pavgusb %%mm3, %%mm1\n" "movq 1(%4), %%mm6\n" /* 8 s+lx +1*/ "pavgusb %%mm4, %%mm0\n" "movq 9(%4), %%mm7\n" /* 8 s+lx +1*/ "pavgusb %%mm5, %%mm1\n" "movq (%2), %%mm2\n" "pavgusb %%mm6, %%mm0\n" "movq 8(%2), %%mm3\n" "pavgusb %%mm2, %%mm0\n" "addl %3, %4\n" "pavgusb %%mm3, %%mm1\n" "movq %%mm0, (%2)\n" "pavgusb %%mm7, %%mm1\n" "movq %%mm6, %%mm2\n" "movq %%mm7, %%mm3\n" "movq %%mm1, 8(%2)\n" "movq %%mm4, %%mm0\n" "movq %%mm5, %%mm1\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); } static inline void rec4ac_mmx(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { __asm__ __volatile__( "movq (%1), %%mm0\n" /* 8 s */ "movq 1(%1), %%mm2\n" /* 8 s +1*/ ".align 8\n" "1:" "movq (%4), %%mm4\n" /* 8 s+lx */ "pavgusb %%mm2, %%mm0\n" "movq 1(%4), %%mm6\n" /* 8 s+lx +1*/ "pavgusb %%mm4, %%mm0\n" "movq (%2), %%mm1\n" /* 8 d */ "pavgusb %%mm6, %%mm0\n" "addl %3, %4\n" "pavgusb %%mm1, %%mm0\n" "movq %%mm6, %%mm2\n" "movq %%mm0, (%2)\n" "movq %%mm4, %%mm0\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); } #else // HAVE_3DNOW static long long ADD_1 = 0x0101010101010101LL; static long long MASK_AND = 0x7f7f7f7f7f7f7f7fLL; #endif static inline void rec_mmx(unsigned char *s, unsigned char *d, int lx2, int h) { __asm__ __volatile__( ".align 8\n" "1:\t" "movq ( %1 ), %%mm0\n" /* 8 s */ "movq 8( %1 ), %%mm2\n" /* 16 s */ "movq %%mm0, ( %2 )\n" "addl %3, %1\n" "movq %%mm2, 8( %2 )\n" "decl %0\n" "leal (%2, %3), %2\n" "jnz 1b" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); } static inline void recc_mmx(unsigned char *s, unsigned char *d, int lx2, int h) { __asm__ __volatile__( ".align 8\n" "1:\t" "movq ( %1 ), %%mm0\n" "addl %3, %1\n" "movq %%mm0, ( %2 )\n" "decl %0\n" "leal (%2, %3), %2\n" "jnz 1b" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); } static inline void reca_mmx(unsigned char *s, unsigned char *d, int lx2, int h) { #ifdef HAVE_3Dnow __asm__ ( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq (%2), %%mm2\n" /* 8 d */ "movq 8(%1), %%mm1\n" /* 8 s */ "movq 8(%2), %%mm3\n" /* 8 d */ "pavgusb %%mm2, %%mm0\n" "addl %3, %1\n" "pavgusb %%mm3, %%mm1\n" "movq %%mm0, (%2)\n" "movq %%mm1, 8(%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); #else /* No 3dnow */ __asm__ ( "movq MASK_AND, %%mm5\n" "movq ADD_1, %%mm6\n" "1:\t" "movq (%1),%%mm0\n" /* Load 16 pixels from each row */ "movq (%2),%%mm1\n" "movq 8(%1),%%mm2\n" "movq 8(%2),%%mm3\n" "psrlw $1,%%mm0\n" /* Shift pixels down */ "psrlw $1,%%mm1\n" "pand %%mm5,%%mm0\n" /* Zero out significant bit */ "psrlw $1,%%mm2\n" "pand %%mm5,%%mm1\n" "psrlw $1,%%mm3\n" "pand %%mm5,%%mm2\n" "paddusb %%mm1,%%mm0\n" /* Add pixels */ "pand %%mm5,%%mm3\n" "paddusb %%mm3,%%mm2\n" "paddusb %%mm6,%%mm0\n" /* Add 1 to results */ "paddusb %%mm6,%%mm2\n" "movq %%mm0,(%2)\n" "addl %3,%1\n" "movq %%mm2, 8(%2)\n" "decl %0\n" "leal (%2, %3), %2\n" "jnz 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); #endif } static inline void recac_mmx(unsigned char *s, unsigned char *d, int lx2, int h) { #ifdef HAVE_3Dnow __asm__ ( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq (%2), %%mm2\n" /* 8 d */ "pavgusb %%mm2, %%mm0\n" "addl %3, %1\n" "movq %%mm0, (%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); #else /* No 3dnow */ __asm__ ( "movq MASK_AND, %%mm5\n" "movq ADD_1, %%mm6\n" "1:\t" "movq (%1),%%mm0\n" "movq (%2),%%mm1\n" "psrlw $1,%%mm0\n" "psrlw $1,%%mm1\n" "pand %%mm5,%%mm0\n" "pand %%mm5,%%mm1\n" "paddusb %%mm1,%%mm0\n" "paddusb %%mm6,%%mm0\n" "addl %3,%1\n" "movq %%mm0,(%2)\n" "decl %0\n" "leal (%2, %3), %2\n" "jnz 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2) ); #endif } static inline void recv_mmx(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { #ifdef HAVE_3Dnow __asm__( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq (%4), %%mm2\n" /* 8 s +lx */ "movq 8(%1), %%mm1\n" /* 8 s */ "movq 8(%4), %%mm3\n" /* 8 s +lx **/ "pavgusb %%mm2, %%mm0\n" "addl %3, %1\n" "pavgusb %%mm3, %%mm1\n" "movq %%mm0, (%2)\n" "addl %3, %4\n" "movq %%mm1, 8(%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); #else __asm__ ( "movq MASK_AND, %%mm5\n" "movq ADD_1, %%mm6\n" "1:\t" "movq (%1), %%mm0\n" /* 8 s */ "movq (%4), %%mm1\n" /* 8 s +lx */ "movq 8(%1), %%mm2\n" /* 8 s */ "movq 8(%4), %%mm3\n" /* 8 s +lx **/ "psrlw $1,%%mm0\n" "psrlw $1,%%mm1\n" "pand %%mm5,%%mm0\n" "psrlw $1,%%mm2\n" "pand %%mm5,%%mm1\n" "psrlw $1,%%mm3\n" "pand %%mm5,%%mm2\n" "paddusb %%mm1,%%mm0\n" "pand %%mm5,%%mm3\n" "paddusb %%mm3,%%mm2\n" "paddusb %%mm6,%%mm0\n" "paddusb %%mm6,%%mm2\n" "movq %%mm0,(%2)\n" "addl %3,%1\n" "movq %%mm2, 8(%2)\n" "addl %3,%4\n" "decl %0\n" "leal (%2, %3), %2\n" "jnz 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); #endif } static inline void recvc_mmx(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { #ifdef HAVE_3Dnow __asm__( ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 s */ "movq (%4), %%mm2\n" /* 8 s +lx */ "addl %3, %1\n" "pavgusb %%mm2, %%mm0\n" "addl %3, %4\n" "movq %%mm0, (%2)\n" "addl %3, %2\n" "loop 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); #else __asm__ ( "movq MASK_AND, %%mm5\n" "movq ADD_1, %%mm6\n" "1:\t" "movq (%1), %%mm0\n" /* 8 s */ "movq (%4), %%mm1\n" /* 8 s +lx */ "psrlw $1,%%mm0\n" "psrlw $1,%%mm1\n" "pand %%mm5,%%mm0\n" "pand %%mm5,%%mm1\n" "paddusb %%mm1,%%mm0\n" "addl %3,%1\n" "paddusb %%mm6,%%mm0\n" "addl %3,%4\n" "movq %%mm0,(%2)\n" "decl %0\n" "leal (%2, %3), %2\n" "jnz 1b\n" : : "c" (h), "r" (s), "r" (d), "r" (lx2), "r" (s +lx) ); #endif } #endif // HAVE_MMX static inline void rec(unsigned char *s, unsigned char *d, int lx2, int h) { int j; for(j = 0; j < h; j++, s += lx2, d += lx2) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; d[4] = s[4]; d[5] = s[5]; d[6] = s[6]; d[7] = s[7]; d[8] = s[8]; d[9] = s[9]; d[10] = s[10]; d[11] = s[11]; d[12] = s[12]; d[13] = s[13]; d[14] = s[14]; d[15] = s[15]; } } static inline void recc(unsigned char *s, unsigned char *d, int lx2, int h) { int j; for(j = 0; j < h; j++, s += lx2, d += lx2) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = s[3]; d[4] = s[4]; d[5] = s[5]; d[6] = s[6]; d[7] = s[7]; } } static inline void reca(unsigned char *s, unsigned char *d, int lx2, int h) { int j; for(j = 0; j < h; j++, s +=lx2, d +=lx2) { d[0] = (unsigned int)(d[0] + s[0] + 1) >> 1; d[1] = (unsigned int)(d[1] + s[1] + 1) >> 1; d[2] = (unsigned int)(d[2] + s[2] + 1) >> 1; d[3] = (unsigned int)(d[3] + s[3] + 1) >> 1; d[4] = (unsigned int)(d[4] + s[4] + 1) >> 1; d[5] = (unsigned int)(d[5] + s[5] + 1) >> 1; d[6] = (unsigned int)(d[6] + s[6] + 1) >> 1; d[7] = (unsigned int)(d[7] + s[7] + 1) >> 1; d[8] = (unsigned int)(d[8] + s[8] + 1) >> 1; d[9] = (unsigned int)(d[9] + s[9] + 1) >> 1; d[10] = (unsigned int)(d[10] + s[10] + 1) >> 1; d[11] = (unsigned int)(d[11] + s[11] + 1) >> 1; d[12] = (unsigned int)(d[12] + s[12] + 1) >> 1; d[13] = (unsigned int)(d[13] + s[13] + 1) >> 1; d[14] = (unsigned int)(d[14] + s[14] + 1) >> 1; d[15] = (unsigned int)(d[15] + s[15] + 1) >> 1; } } static inline void recac(unsigned char *s, unsigned char *d, int lx2, int h) { int j; for(j = 0; j < h; j++, s += lx2, d += lx2) { d[0] = (unsigned int)(d[0] + s[0] + 1)>>1; d[1] = (unsigned int)(d[1] + s[1] + 1)>>1; d[2] = (unsigned int)(d[2] + s[2] + 1)>>1; d[3] = (unsigned int)(d[3] + s[3] + 1)>>1; d[4] = (unsigned int)(d[4] + s[4] + 1)>>1; d[5] = (unsigned int)(d[5] + s[5] + 1)>>1; d[6] = (unsigned int)(d[6] + s[6] + 1)>>1; d[7] = (unsigned int)(d[7] + s[7] + 1)>>1; } } static inline void recv(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { unsigned char *dp,*sp,*sp2; int j; sp = s; sp2 = s + lx; dp = d; for(j = 0; j < h; j++) { dp[0] = (unsigned int)(sp[0] + sp2[0] + 1) >> 1; dp[1] = (unsigned int)(sp[1] + sp2[1] + 1) >> 1; dp[2] = (unsigned int)(sp[2] + sp2[2] + 1) >> 1; dp[3] = (unsigned int)(sp[3] + sp2[3] + 1) >> 1; dp[4] = (unsigned int)(sp[4] + sp2[4] + 1) >> 1; dp[5] = (unsigned int)(sp[5] + sp2[5] + 1) >> 1; dp[6] = (unsigned int)(sp[6] + sp2[6] + 1) >> 1; dp[7] = (unsigned int)(sp[7] + sp2[7] + 1) >> 1; dp[8] = (unsigned int)(sp[8] + sp2[8] + 1) >> 1; dp[9] = (unsigned int)(sp[9] + sp2[9] + 1) >> 1; dp[10] = (unsigned int)(sp[10] + sp2[10] + 1) >> 1; dp[11] = (unsigned int)(sp[11] + sp2[11] + 1) >> 1; dp[12] = (unsigned int)(sp[12] + sp2[12] + 1) >> 1; dp[13] = (unsigned int)(sp[13] + sp2[13] + 1) >> 1; dp[14] = (unsigned int)(sp[14] + sp2[14] + 1) >> 1; dp[15] = (unsigned int)(sp[15] + sp2[15] + 1) >> 1; sp+= lx2; sp2+= lx2; dp+= lx2; } } static inline void recvc(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { unsigned char *dp,*sp,*sp2; int j; sp = s; sp2 = s+lx; dp = d; for(j = 0; j < h; j++) { dp[0] = (unsigned int)(sp[0]+sp2[0]+1)>>1; dp[1] = (unsigned int)(sp[1]+sp2[1]+1)>>1; dp[2] = (unsigned int)(sp[2]+sp2[2]+1)>>1; dp[3] = (unsigned int)(sp[3]+sp2[3]+1)>>1; dp[4] = (unsigned int)(sp[4]+sp2[4]+1)>>1; dp[5] = (unsigned int)(sp[5]+sp2[5]+1)>>1; dp[6] = (unsigned int)(sp[6]+sp2[6]+1)>>1; dp[7] = (unsigned int)(sp[7]+sp2[7]+1)>>1; sp+= lx2; sp2+= lx2; dp+= lx2; } } static inline void recva(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { unsigned char *dp,*sp,*sp2; int j; sp = s; sp2 = s+lx; dp = d; for (j=0; j>1) + 1)>>1; dp[1] = (dp[1] + ((unsigned int)(sp[1]+sp2[1]+1)>>1) + 1)>>1; dp[2] = (dp[2] + ((unsigned int)(sp[2]+sp2[2]+1)>>1) + 1)>>1; dp[3] = (dp[3] + ((unsigned int)(sp[3]+sp2[3]+1)>>1) + 1)>>1; dp[4] = (dp[4] + ((unsigned int)(sp[4]+sp2[4]+1)>>1) + 1)>>1; dp[5] = (dp[5] + ((unsigned int)(sp[5]+sp2[5]+1)>>1) + 1)>>1; dp[6] = (dp[6] + ((unsigned int)(sp[6]+sp2[6]+1)>>1) + 1)>>1; dp[7] = (dp[7] + ((unsigned int)(sp[7]+sp2[7]+1)>>1) + 1)>>1; dp[8] = (dp[8] + ((unsigned int)(sp[8]+sp2[8]+1)>>1) + 1)>>1; dp[9] = (dp[9] + ((unsigned int)(sp[9]+sp2[9]+1)>>1) + 1)>>1; dp[10] = (dp[10] + ((unsigned int)(sp[10]+sp2[10]+1)>>1) + 1)>>1; dp[11] = (dp[11] + ((unsigned int)(sp[11]+sp2[11]+1)>>1) + 1)>>1; dp[12] = (dp[12] + ((unsigned int)(sp[12]+sp2[12]+1)>>1) + 1)>>1; dp[13] = (dp[13] + ((unsigned int)(sp[13]+sp2[13]+1)>>1) + 1)>>1; dp[14] = (dp[14] + ((unsigned int)(sp[14]+sp2[14]+1)>>1) + 1)>>1; dp[15] = (dp[15] + ((unsigned int)(sp[15]+sp2[15]+1)>>1) + 1)>>1; sp+= lx2; sp2+= lx2; dp+= lx2; } } static inline void recvac(unsigned char *s, unsigned char *d, int lx,int lx2, int h){ unsigned char *dp,*sp,*sp2; int j; sp = s; sp2 = s+lx; dp = d; for (j=0; j>1) + 1)>>1; dp[1] = (dp[1] + ((unsigned int)(sp[1]+sp2[1]+1)>>1) + 1)>>1; dp[2] = (dp[2] + ((unsigned int)(sp[2]+sp2[2]+1)>>1) + 1)>>1; dp[3] = (dp[3] + ((unsigned int)(sp[3]+sp2[3]+1)>>1) + 1)>>1; dp[4] = (dp[4] + ((unsigned int)(sp[4]+sp2[4]+1)>>1) + 1)>>1; dp[5] = (dp[5] + ((unsigned int)(sp[5]+sp2[5]+1)>>1) + 1)>>1; dp[6] = (dp[6] + ((unsigned int)(sp[6]+sp2[6]+1)>>1) + 1)>>1; dp[7] = (dp[7] + ((unsigned int)(sp[7]+sp2[7]+1)>>1) + 1)>>1; sp+= lx2; sp2+= lx2; dp+= lx2; } } static inline void rech(unsigned char *s, unsigned char *d, int lx2, int h){ unsigned char *dp,*sp; unsigned int s1,s2; int j; sp = s; dp = d; for (j=0; j>1; dp[1] = (unsigned int)(s2+(s1=sp[2])+1)>>1; dp[2] = (unsigned int)(s1+(s2=sp[3])+1)>>1; dp[3] = (unsigned int)(s2+(s1=sp[4])+1)>>1; dp[4] = (unsigned int)(s1+(s2=sp[5])+1)>>1; dp[5] = (unsigned int)(s2+(s1=sp[6])+1)>>1; dp[6] = (unsigned int)(s1+(s2=sp[7])+1)>>1; dp[7] = (unsigned int)(s2+(s1=sp[8])+1)>>1; dp[8] = (unsigned int)(s1+(s2=sp[9])+1)>>1; dp[9] = (unsigned int)(s2+(s1=sp[10])+1)>>1; dp[10] = (unsigned int)(s1+(s2=sp[11])+1)>>1; dp[11] = (unsigned int)(s2+(s1=sp[12])+1)>>1; dp[12] = (unsigned int)(s1+(s2=sp[13])+1)>>1; dp[13] = (unsigned int)(s2+(s1=sp[14])+1)>>1; dp[14] = (unsigned int)(s1+(s2=sp[15])+1)>>1; dp[15] = (unsigned int)(s2+sp[16]+1)>>1; sp+= lx2; dp+= lx2; } } static inline void rechc(unsigned char *s,unsigned char *d, int lx2, int h){ unsigned char *dp,*sp; unsigned int s1,s2; int j; sp = s; dp = d; for (j=0; j>1; dp[1] = (unsigned int)(s2+(s1=sp[2])+1)>>1; dp[2] = (unsigned int)(s1+(s2=sp[3])+1)>>1; dp[3] = (unsigned int)(s2+(s1=sp[4])+1)>>1; dp[4] = (unsigned int)(s1+(s2=sp[5])+1)>>1; dp[5] = (unsigned int)(s2+(s1=sp[6])+1)>>1; dp[6] = (unsigned int)(s1+(s2=sp[7])+1)>>1; dp[7] = (unsigned int)(s2+sp[8]+1)>>1; sp+= lx2; dp+= lx2; } } static inline void recha(unsigned char *s, unsigned char *d,int lx2, int h) { unsigned char *dp,*sp; unsigned int s1,s2; int j; sp = s; dp = d; for (j = 0; j < h; j++) { s1 = sp[0]; dp[0] = (dp[0] + ((unsigned int)(s1 + (s2 = sp[1]) + 1) >> 1) + 1) >> 1; dp[1] = (dp[1] + ((unsigned int)(s2 + (s1 = sp[2]) + 1) >> 1) + 1) >> 1; dp[2] = (dp[2] + ((unsigned int)(s1 + (s2 = sp[3]) + 1) >> 1) + 1) >> 1; dp[3] = (dp[3] + ((unsigned int)(s2 + (s1 = sp[4]) + 1) >> 1) + 1) >> 1; dp[4] = (dp[4] + ((unsigned int)(s1 + (s2 = sp[5]) + 1) >> 1) + 1) >> 1; dp[5] = (dp[5] + ((unsigned int)(s2 + (s1 = sp[6]) + 1) >> 1) + 1) >> 1; dp[6] = (dp[6] + ((unsigned int)(s1 + (s2 = sp[7]) + 1) >> 1) + 1) >> 1; dp[7] = (dp[7] + ((unsigned int)(s2 + (s1 = sp[8]) + 1) >> 1) + 1) >> 1; dp[8] = (dp[8] + ((unsigned int)(s1 + (s2 = sp[9]) + 1) >> 1) + 1) >> 1; dp[9] = (dp[9] + ((unsigned int)(s2 + (s1 = sp[10]) + 1) >> 1) + 1) >> 1; dp[10] = (dp[10] + ((unsigned int)(s1 + (s2 = sp[11]) + 1) >> 1) + 1) >> 1; dp[11] = (dp[11] + ((unsigned int)(s2 + (s1 = sp[12]) + 1) >> 1) + 1) >> 1; dp[12] = (dp[12] + ((unsigned int)(s1 + (s2 = sp[13]) + 1) >> 1) + 1) >> 1; dp[13] = (dp[13] + ((unsigned int)(s2 + (s1 = sp[14]) + 1) >> 1) + 1) >> 1; dp[14] = (dp[14] + ((unsigned int)(s1 + (s2 = sp[15]) + 1) >> 1) + 1) >> 1; dp[15] = (dp[15] + ((unsigned int)(s2 + sp[16] + 1) >> 1) + 1) >> 1; sp += lx2; dp += lx2; } } static inline void rechac(unsigned char *s,unsigned char *d, int lx2, int h) { unsigned char *dp,*sp; unsigned int s1,s2; int j; sp = s; dp = d; for(j = 0; j < h; j++) { s1 = sp[0]; dp[0] = (dp[0] + ((unsigned int)(s1 + (s2 = sp[1]) + 1) >> 1) + 1) >> 1; dp[1] = (dp[1] + ((unsigned int)(s2 + (s1 = sp[2]) + 1) >> 1) + 1) >> 1; dp[2] = (dp[2] + ((unsigned int)(s1 + (s2 = sp[3]) + 1) >> 1) + 1) >> 1; dp[3] = (dp[3] + ((unsigned int)(s2 + (s1 = sp[4]) + 1) >> 1) + 1) >> 1; dp[4] = (dp[4] + ((unsigned int)(s1 + (s2 = sp[5]) + 1) >> 1) + 1) >> 1; dp[5] = (dp[5] + ((unsigned int)(s2 + (s1 = sp[6]) + 1) >> 1) + 1) >> 1; dp[6] = (dp[6] + ((unsigned int)(s1 + (s2 = sp[7]) + 1) >> 1) + 1) >> 1; dp[7] = (dp[7] + ((unsigned int)(s2 + sp[8] + 1) >> 1) + 1) >> 1; sp += lx2; dp += lx2; } } static inline void rec4(unsigned char *s, unsigned char *d, int lx, int lx2, int h) { unsigned char *dp,*sp,*sp2; unsigned int s1,s2,s3,s4; int j; sp = s; sp2 = s+lx; dp = d; for (j=0; j>2; dp[1] = (unsigned int)(s2+(s1=sp[2])+s4+(s3=sp2[2])+2)>>2; dp[2] = (unsigned int)(s1+(s2=sp[3])+s3+(s4=sp2[3])+2)>>2; dp[3] = (unsigned int)(s2+(s1=sp[4])+s4+(s3=sp2[4])+2)>>2; dp[4] = (unsigned int)(s1+(s2=sp[5])+s3+(s4=sp2[5])+2)>>2; dp[5] = (unsigned int)(s2+(s1=sp[6])+s4+(s3=sp2[6])+2)>>2; dp[6] = (unsigned int)(s1+(s2=sp[7])+s3+(s4=sp2[7])+2)>>2; dp[7] = (unsigned int)(s2+(s1=sp[8])+s4+(s3=sp2[8])+2)>>2; dp[8] = (unsigned int)(s1+(s2=sp[9])+s3+(s4=sp2[9])+2)>>2; dp[9] = (unsigned int)(s2+(s1=sp[10])+s4+(s3=sp2[10])+2)>>2; dp[10] = (unsigned int)(s1+(s2=sp[11])+s3+(s4=sp2[11])+2)>>2; dp[11] = (unsigned int)(s2+(s1=sp[12])+s4+(s3=sp2[12])+2)>>2; dp[12] = (unsigned int)(s1+(s2=sp[13])+s3+(s4=sp2[13])+2)>>2; dp[13] = (unsigned int)(s2+(s1=sp[14])+s4+(s3=sp2[14])+2)>>2; dp[14] = (unsigned int)(s1+(s2=sp[15])+s3+(s4=sp2[15])+2)>>2; dp[15] = (unsigned int)(s2+sp[16]+s4+sp2[16]+2)>>2; sp+= lx2; sp2+= lx2; dp+= lx2; } } static inline void rec4c(unsigned char *s,unsigned char *d, int lx, int lx2, int h) { unsigned char *dp,*sp,*sp2; unsigned int s1,s2,s3,s4; int j; sp = s; sp2 = s+lx; dp = d; for (j=0; j>2; dp[1] = (unsigned int)(s2+(s1=sp[2])+s4+(s3=sp2[2])+2)>>2; dp[2] = (unsigned int)(s1+(s2=sp[3])+s3+(s4=sp2[3])+2)>>2; dp[3] = (unsigned int)(s2+(s1=sp[4])+s4+(s3=sp2[4])+2)>>2; dp[4] = (unsigned int)(s1+(s2=sp[5])+s3+(s4=sp2[5])+2)>>2; dp[5] = (unsigned int)(s2+(s1=sp[6])+s4+(s3=sp2[6])+2)>>2; dp[6] = (unsigned int)(s1+(s2=sp[7])+s3+(s4=sp2[7])+2)>>2; dp[7] = (unsigned int)(s2+sp[8]+s4+sp2[8]+2)>>2; sp+= lx2; sp2+= lx2; dp+= lx2; } } static inline void rec4a(unsigned char *s,unsigned char *d, int lx, int lx2, int h) { unsigned char *dp=d, *sp=s, *sp2=s+lx; unsigned int s1, s2, s3, s4; int j; /* sp = s; sp2 = s+lx; dp = d; */ for (j=0; j>2) + 1)>>1; dp[1] = (dp[1] + ((unsigned int)(s2+(s1=sp[2])+s4+(s3=sp2[2])+2)>>2) + 1)>>1; dp[2] = (dp[2] + ((unsigned int)(s1+(s2=sp[3])+s3+(s4=sp2[3])+2)>>2) + 1)>>1; dp[3] = (dp[3] + ((unsigned int)(s2+(s1=sp[4])+s4+(s3=sp2[4])+2)>>2) + 1)>>1; dp[4] = (dp[4] + ((unsigned int)(s1+(s2=sp[5])+s3+(s4=sp2[5])+2)>>2) + 1)>>1; dp[5] = (dp[5] + ((unsigned int)(s2+(s1=sp[6])+s4+(s3=sp2[6])+2)>>2) + 1)>>1; dp[6] = (dp[6] + ((unsigned int)(s1+(s2=sp[7])+s3+(s4=sp2[7])+2)>>2) + 1)>>1; dp[7] = (dp[7] + ((unsigned int)(s2+(s1=sp[8])+s4+(s3=sp2[8])+2)>>2) + 1)>>1; dp[8] = (dp[8] + ((unsigned int)(s1+(s2=sp[9])+s3+(s4=sp2[9])+2)>>2) + 1)>>1; dp[9] = (dp[9] + ((unsigned int)(s2+(s1=sp[10])+s4+(s3=sp2[10])+2)>>2) + 1)>>1; dp[10] = (dp[10] + ((unsigned int)(s1+(s2=sp[11])+s3+(s4=sp2[11])+2)>>2) + 1)>>1; dp[11] = (dp[11] + ((unsigned int)(s2+(s1=sp[12])+s4+(s3=sp2[12])+2)>>2) + 1)>>1; dp[12] = (dp[12] + ((unsigned int)(s1+(s2=sp[13])+s3+(s4=sp2[13])+2)>>2) + 1)>>1; dp[13] = (dp[13] + ((unsigned int)(s2+(s1=sp[14])+s4+(s3=sp2[14])+2)>>2) + 1)>>1; dp[14] = (dp[14] + ((unsigned int)(s1+(s2=sp[15])+s3+(s4=sp2[15])+2)>>2) + 1)>>1; dp[15] = (dp[15] + ((unsigned int)(s2+sp[16]+s4+sp2[16]+2)>>2) + 1)>>1; sp+= lx2; sp2+= lx2; dp+= lx2; } } static inline void rec4ac(unsigned char *s,unsigned char *d, int lx, int lx2, int h) { unsigned char *dp=d, *sp=s, *sp2=s+lx; unsigned int s1,s2,s3,s4; int j; /* sp = s; sp2 = s+lx; dp = d; */ for (j=0; j>2) + 1)>>1; dp[1] = (dp[1] + ((unsigned int)(s2+(s1=sp[2])+s4+(s3=sp2[2])+2)>>2) + 1)>>1; dp[2] = (dp[2] + ((unsigned int)(s1+(s2=sp[3])+s3+(s4=sp2[3])+2)>>2) + 1)>>1; dp[3] = (dp[3] + ((unsigned int)(s2+(s1=sp[4])+s4+(s3=sp2[4])+2)>>2) + 1)>>1; dp[4] = (dp[4] + ((unsigned int)(s1+(s2=sp[5])+s3+(s4=sp2[5])+2)>>2) + 1)>>1; dp[5] = (dp[5] + ((unsigned int)(s2+(s1=sp[6])+s4+(s3=sp2[6])+2)>>2) + 1)>>1; dp[6] = (dp[6] + ((unsigned int)(s1+(s2=sp[7])+s3+(s4=sp2[7])+2)>>2) + 1)>>1; dp[7] = (dp[7] + ((unsigned int)(s2+sp[8]+s4+sp2[8]+2)>>2) + 1)>>1; sp+= lx2; sp2+= lx2; dp+= lx2; } } static inline void recon_comp(mpeg3video_t *video, unsigned char *src, unsigned char *dst, int lx, int lx2, int w, int h, int x, int y, int dx, int dy, int addflag) { int switcher; unsigned char *s, *d; /* half pel scaling */ switcher = (dx & 1) << 3 | (dy & 1) << 2 | w; if(addflag) switcher |= 2; /* origins */ s = src + lx * (y + (dy >> 1)) + x + (dx >> 1); d = dst + lx * y + x; // Accelerated functions #ifdef HAVE_MMX if(video->have_mmx) { switch(switcher) { case 0x3: reca_mmx(s, d, lx2, h); break; case 0x2: recac_mmx(s, d, lx2, h); break; case 0x1: rec_mmx(s, d, lx2, h); break; case 0x0: recc_mmx(s, d, lx2, h); break; case 0x7: recva_mmx(s, d, lx, lx2, h); break; case 0x6: recvac_mmx(s, d, lx, lx2, h); break; case 0x5: recv_mmx(s, d, lx, lx2, h); break; case 0x4: recvc_mmx(s, d, lx, lx2, h); break; case 0x9: rech_mmx(s, d, lx2, h); break; case 0x8: rechc_mmx(s, d, lx2, h); break; } } else #endif { switch(switcher) { case 0x3: reca(s, d, lx2, h); break; case 0x2: recac(s, d, lx2, h); break; case 0x1: rec(s, d, lx2, h); break; case 0x0: recc(s, d, lx2, h); break; case 0x7: recva(s, d, lx, lx2, h); break; case 0x6: recvac(s, d, lx, lx2, h); break; case 0x5: recv(s, d, lx, lx2, h); break; case 0x4: recvc(s, d, lx, lx2, h); break; case 0x9: rech(s, d, lx2, h); break; case 0x8: rechc(s, d, lx2, h); break; } } // Unaccelerated functions switch(switcher) { case 0xb: recha(s, d, lx2, h); break; case 0xa: rechac(s, d, lx2, h); break; case 0xf: rec4a(s, d, lx, lx2, h); break; case 0xe: rec4ac(s, d, lx, lx2, h); break; case 0xd: rec4(s, d, lx, lx2, h); break; case 0xc: rec4c(s, d, lx, lx2, h); break; } } /* unsigned char *src[]; * prediction source buffer * int sfield; * prediction source field number (0 or 1) * unsigned char *dst[]; * prediction destination buffer * int dfield; * prediction destination field number (0 or 1)* int lx,lx2; * horizontal offsets * int w,h; * prediction block/sub-block width, height * int x,y; * pixel co-ordinates of top-left sample in current MB * int dx,dy; * horizontal, vertical motion vector * int addflag; * add prediction error to prediction ? * */ static void recon(mpeg3video_t *video, unsigned char *src[], int sfield, unsigned char *dst[], int dfield, int lx, int lx2, int w, int h, int x, int y, int dx, int dy, int addflag) { /* Y */ recon_comp(video, (src[0] + (sfield ? (lx2 >> 1) : 0)), dst[0] + (dfield ? (lx2 >> 1) : 0), lx, lx2, w, h, x, y, dx, dy, addflag); if(video->chroma_format != CHROMA444) { lx >>= 1; dx /= 2; lx2 >>= 1; w = 0; x >>= 1; } if(video->chroma_format == CHROMA420) { h >>= 1; dy /= 2; y >>= 1; } /* Cb */ recon_comp(video, (src[1] + (sfield ? (lx2 >> 1) : 0)), dst[1] + (dfield ? (lx2 >> 1) : 0), lx, lx2, w, h, x, y, dx, dy, addflag); /* Cr */ recon_comp(video, (src[2] + (sfield ? (lx2 >> 1) : 0)), dst[2] + (dfield ? (lx2 >> 1) : 0), lx, lx2, w, h, x, y, dx, dy, addflag); } #define WIDTH 1 int mpeg3video_reconstruct(mpeg3video_t *video, int bx, int by, int mb_type, int motion_type, int PMV[2][2][2], int mv_field_sel[2][2], int dmvector[2], int stwtype) { int currentfield; unsigned char **predframe; int DMV[2][2]; int stwtop, stwbot; stwtop = stwtype % 3; /* 0:temporal, 1 : (spat+temp) / 2, 2 : spatial */ stwbot = stwtype / 3; if((mb_type & MB_FORWARD) || (video->pict_type == P_TYPE)) { if(video->pict_struct == FRAME_PICTURE) { if((motion_type == MC_FRAME) || !(mb_type & MB_FORWARD)) { /* frame-based prediction */ { if(stwtop < 2) recon(video, video->oldrefframe, 0, video->newframe, 0, video->coded_picture_width, video->coded_picture_width << 1, WIDTH, 8, bx, by, PMV[0][0][0], PMV[0][0][1], stwtop); if(stwbot < 2) recon(video, video->oldrefframe, 1, video->newframe, 1, video->coded_picture_width, video->coded_picture_width << 1, WIDTH, 8, bx, by, PMV[0][0][0], PMV[0][0][1], stwbot); } } else if(motion_type == MC_FIELD) /* field-based prediction */ { /* top field prediction */ if(stwtop < 2) recon(video, video->oldrefframe, mv_field_sel[0][0], video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 8, bx, by >> 1, PMV[0][0][0], PMV[0][0][1] >> 1, stwtop); /* bottom field prediction */ if(stwbot < 2) recon(video, video->oldrefframe, mv_field_sel[1][0], video->newframe, 1, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 8, bx, by >> 1, PMV[1][0][0], PMV[1][0][1] >> 1, stwbot); } else if(motion_type == MC_DMV) { /* dual prime prediction */ /* calculate derived motion vectors */ mpeg3video_calc_dmv(video, DMV, dmvector, PMV[0][0][0], PMV[0][0][1] >> 1); if(stwtop < 2) { /* predict top field from top field */ recon(video, video->oldrefframe, 0, video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 8, bx, by>>1, PMV[0][0][0], PMV[0][0][1] >> 1, 0); /* predict and add to top field from bottom field */ recon(video, video->oldrefframe, 1, video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 8, bx, by>>1, DMV[0][0], DMV[0][1], 1); } if(stwbot < 2) { /* predict bottom field from bottom field */ recon(video, video->oldrefframe, 1, video->newframe, 1, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 8, bx, by>>1, PMV[0][0][0], PMV[0][0][1]>>1, 0); /* predict and add to bottom field from top field */ recon(video, video->oldrefframe, 0, video->newframe, 1, video->coded_picture_width << 1, video->coded_picture_width<<1, WIDTH, 8, bx, by>>1, DMV[1][0], DMV[1][1], 1); } } else /* invalid motion_type */ /* fprintf(stderr, "reconstruct: invalid motion_type\n"); */ ; } else { /* TOP_FIELD or BOTTOM_FIELD */ /* field picture */ currentfield = (video->pict_struct == BOTTOM_FIELD); /* determine which frame to use for prediction */ if((video->pict_type == P_TYPE) && video->secondfield && (currentfield != mv_field_sel[0][0])) predframe = video->refframe; /* same frame */ else predframe = video->oldrefframe; /* previous frame */ if((motion_type == MC_FIELD) || !(mb_type & MB_FORWARD)) { /* field-based prediction */ if(stwtop < 2) recon(video, predframe,mv_field_sel[0][0],video->newframe,0, video->coded_picture_width << 1,video->coded_picture_width << 1,WIDTH,16,bx,by, PMV[0][0][0],PMV[0][0][1],stwtop); } else if(motion_type == MC_16X8) { if(stwtop < 2) { recon(video, predframe, mv_field_sel[0][0], video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 8, bx, by, PMV[0][0][0], PMV[0][0][1], stwtop); /* determine which frame to use for lower half prediction */ if((video->pict_type==P_TYPE) && video->secondfield && (currentfield!=mv_field_sel[1][0])) predframe = video->refframe; /* same frame */ else predframe = video->oldrefframe; /* previous frame */ recon(video, predframe, mv_field_sel[1][0], video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 8, bx, by+8, PMV[1][0][0], PMV[1][0][1], stwtop); } } else if(motion_type == MC_DMV) /* dual prime prediction */ { if(video->secondfield) predframe = video->refframe; /* same frame */ else predframe = video->oldrefframe; /* previous frame */ /* calculate derived motion vectors */ mpeg3video_calc_dmv(video, DMV, dmvector, PMV[0][0][0], PMV[0][0][1]); /* predict from field of same parity */ recon(video, video->oldrefframe, currentfield, video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 16, bx, by, PMV[0][0][0], PMV[0][0][1], 0); /* predict from field of opposite parity */ recon(video, predframe, !currentfield, video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 16, bx, by, DMV[0][0], DMV[0][1], 1); } else /* invalid motion_type */ /* fprintf(stderr, "reconstruct: invalid motion_type\n"); */ ; } stwtop = stwbot = 1; } if(mb_type & MB_BACKWARD) { if(video->pict_struct == FRAME_PICTURE) { if(motion_type == MC_FRAME) { /* frame-based prediction */ if(stwtop < 2) recon(video, video->refframe, 0, video->newframe, 0, video->coded_picture_width, video->coded_picture_width << 1, WIDTH, 8, bx, by, PMV[0][1][0], PMV[0][1][1], stwtop); if(stwbot < 2) recon(video, video->refframe, 1, video->newframe, 1, video->coded_picture_width, video->coded_picture_width << 1, WIDTH, 8, bx, by, PMV[0][1][0], PMV[0][1][1], stwbot); } else { /* field-based prediction */ /* top field prediction */ if(stwtop < 2) { recon(video, video->refframe, mv_field_sel[0][1], video->newframe, 0, (video->coded_picture_width << 1), (video->coded_picture_width<<1), WIDTH, 8, bx, (by >> 1), PMV[0][1][0], (PMV[0][1][1] >> 1), stwtop); } /* bottom field prediction */ if(stwbot < 2) { recon(video, video->refframe, mv_field_sel[1][1], video->newframe, 1, (video->coded_picture_width << 1), (video->coded_picture_width << 1), WIDTH, 8, bx, (by>>1), PMV[1][1][0], (PMV[1][1][1]>>1), stwbot); } } } else { /* TOP_FIELD or BOTTOM_FIELD */ /* field picture */ if(motion_type == MC_FIELD) { /* field-based prediction */ recon(video, video->refframe, mv_field_sel[0][1], video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 16, bx, by, PMV[0][1][0], PMV[0][1][1], stwtop); } else if(motion_type==MC_16X8) { recon(video, video->refframe, mv_field_sel[0][1], video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 8, bx, by, PMV[0][1][0], PMV[0][1][1], stwtop); recon(video, video->refframe, mv_field_sel[1][1], video->newframe, 0, video->coded_picture_width << 1, video->coded_picture_width << 1, WIDTH, 8, bx, by+8, PMV[1][1][0], PMV[1][1][1], stwtop); } else /* invalid motion_type */ /* fprintf(stderr, "reconstruct: invalid motion_type\n"); */ ; } } /* mb_type & MB_BACKWARD */ return 0; } libmpeg3-1.5.4/video/seek.c0000644000175000017500000002721507766716300015663 0ustar enderender00000000000000#include "../mpeg3private.h" #include "../mpeg3protos.h" #include "mpeg3video.h" #include #include void mpeg3video_toc_error() { fprintf(stderr, "mpeg3video_seek: frame accurate seeking without a table of contents \n" "is no longer supported. Use mpeg3toc \n" "to generate a table of contents and load the table of contents instead.\n"); } unsigned int mpeg3bits_next_startcode(mpeg3_bits_t* stream) { /* Perform forwards search */ mpeg3bits_byte_align(stream); /* * printf("mpeg3bits_next_startcode 1 %lld %lld\n", * stream->demuxer->titles[0]->fs->current_byte, * stream->demuxer->titles[0]->fs->total_bytes); * */ //mpeg3_read_next_packet(stream->demuxer); //printf("mpeg3bits_next_startcode 2 %d %d\n", // stream->demuxer->titles[0]->fs->current_byte, // stream->demuxer->titles[0]->fs->total_bytes); //printf("mpeg3bits_next_startcode 2 %llx\n", mpeg3bits_tell(stream)); /* Perform search */ while(1) { unsigned int code = mpeg3bits_showbits32_noptr(stream); if((code >> 8) == MPEG3_PACKET_START_CODE_PREFIX) break; if(mpeg3bits_eof(stream)) break; mpeg3bits_getbyte_noptr(stream); /* * printf("mpeg3bits_next_startcode 3 %08x %d %d\n", * mpeg3bits_showbits32_noptr(stream), * stream->demuxer->titles[0]->fs->current_byte, * stream->demuxer->titles[0]->fs->total_bytes); */ } //printf("mpeg3bits_next_startcode 4 %d %d\n", // stream->demuxer->titles[0]->fs->current_byte, // stream->demuxer->titles[0]->fs->total_bytes); return mpeg3bits_showbits32_noptr(stream); } /* Line up on the beginning of the next code. */ int mpeg3video_next_code(mpeg3_bits_t* stream, unsigned int code) { while(!mpeg3bits_eof(stream) && mpeg3bits_showbits32_noptr(stream) != code) { mpeg3bits_getbyte_noptr(stream); } return mpeg3bits_eof(stream); } /* Line up on the beginning of the previous code. */ int mpeg3video_prev_code(mpeg3_demuxer_t *demuxer, unsigned int code) { uint32_t current_code = 0; #define PREV_CODE_MACRO \ { \ current_code >>= 8; \ current_code |= ((uint32_t)mpeg3demux_read_prev_char(demuxer)) << 24; \ } PREV_CODE_MACRO PREV_CODE_MACRO PREV_CODE_MACRO PREV_CODE_MACRO while(!mpeg3demux_bof(demuxer) && current_code != code) { PREV_CODE_MACRO } return mpeg3demux_bof(demuxer); } long mpeg3video_goptimecode_to_frame(mpeg3video_t *video) { /* printf("mpeg3video_goptimecode_to_frame %d %d %d %d %f\n", */ /* video->gop_timecode.hour, video->gop_timecode.minute, video->gop_timecode.second, video->gop_timecode.frame, video->frame_rate); */ return (long)(video->gop_timecode.hour * 3600 * video->frame_rate + video->gop_timecode.minute * 60 * video->frame_rate + video->gop_timecode.second * video->frame_rate + video->gop_timecode.frame) - 1 - video->first_frame; } int mpeg3video_match_refframes(mpeg3video_t *video) { unsigned char *dst, *src; int i, j, size; for(i = 0; i < 3; i++) { if(video->newframe[i]) { if(video->newframe[i] == video->refframe[i]) { src = video->refframe[i]; dst = video->oldrefframe[i]; } else { src = video->oldrefframe[i]; dst = video->refframe[i]; } if(i == 0) size = video->coded_picture_width * video->coded_picture_height + 32 * video->coded_picture_width; else size = video->chrom_width * video->chrom_height + 32 * video->chrom_width; memcpy(dst, src, size); } } return 0; } int mpeg3video_seek_byte(mpeg3video_t *video, int64_t byte) { mpeg3_t *file = video->file; mpeg3_bits_t *vstream = video->vstream; mpeg3_demuxer_t *demuxer = vstream->demuxer; video->byte_seek = byte; // Need PTS now so audio can be synchronized mpeg3bits_seek_byte(vstream, byte); // file->percentage_pts = mpeg3demux_scan_pts(demuxer); return 0; } int mpeg3video_seek_frame(mpeg3video_t *video, long frame) { video->frame_seek = frame; return 0; } int mpeg3video_seek(mpeg3video_t *video) { long this_gop_start; int result = 0; int back_step; int attempts; mpeg3_t *file = video->file; mpeg3_bits_t *vstream = video->vstream; mpeg3_vtrack_t *track = video->track; mpeg3_demuxer_t *demuxer = vstream->demuxer; int64_t byte; long frame_number; int match_refframes = 1; /* Must do seeking here so files which don't use video don't seek. */ /* Seeking is done in the demuxer */ /* Seek to absolute byte */ if(video->byte_seek >= 0) { byte = video->byte_seek; video->byte_seek = -1; mpeg3demux_seek_byte(demuxer, byte); // Rewind 2 I-frames if(byte > 0) { //printf("mpeg3video_seek 1\n"); mpeg3demux_start_reverse(demuxer); //printf("mpeg3video_seek 1 %lld\n", mpeg3demux_tell_byte(demuxer)); if(!result) { if(video->has_gops) result = mpeg3video_prev_code(demuxer, MPEG3_GOP_START_CODE); else result = mpeg3video_prev_code(demuxer, MPEG3_SEQUENCE_START_CODE); } //printf("mpeg3video_seek 2 %lld\n", mpeg3demux_tell_byte(demuxer)); if(!result) { if(video->has_gops) result = mpeg3video_prev_code(demuxer, MPEG3_GOP_START_CODE); else result = mpeg3video_prev_code(demuxer, MPEG3_SEQUENCE_START_CODE); } //printf("mpeg3video_seek 3 %lld\n", mpeg3demux_tell_byte(demuxer)); mpeg3demux_start_forward(demuxer); } else { // Read first frame video->repeat_count = 0; mpeg3bits_reset(vstream); mpeg3video_read_frame_backend(video, 0); mpeg3bits_seek_byte(vstream, 0); video->repeat_count = 0; } mpeg3bits_reset(vstream); //printf("mpeg3video_seek 4 %lld\n", mpeg3demux_tell_byte(demuxer)); // Read up to the correct byte result = 0; video->repeat_count = 0; while(!result && !mpeg3demux_eof(demuxer) && mpeg3demux_tell_byte(demuxer) < byte) { result = mpeg3video_read_frame_backend(video, 0); } //printf("mpeg3video_seek 5 %lld\n", mpeg3demux_tell_byte(demuxer)); mpeg3demux_reset_pts(demuxer); //printf("mpeg3video_seek 10\n"); } else /* Seek to a frame */ if(video->frame_seek >= 0) { frame_number = video->frame_seek; video->frame_seek = -1; if(frame_number < 0) frame_number = 0; if(frame_number > video->maxframe) frame_number = video->maxframe; //printf("mpeg3video_seek 1 %ld %ld\n", frame_number, video->framenum); /* Seek to I frame in table of contents */ if(track->frame_offsets) { if((frame_number < video->framenum || frame_number - video->framenum > MPEG3_SEEK_THRESHOLD)) { int i; for(i = track->total_keyframe_numbers - 1; i >= 0; i--) { if(track->keyframe_numbers[i] <= frame_number) { int frame; int64_t byte; // Go 2 I-frames before current position if(i > 0) i--; frame = track->keyframe_numbers[i]; if(frame == 0) byte = 0; else byte = track->frame_offsets[frame]; video->framenum = track->keyframe_numbers[i]; mpeg3bits_seek_byte(vstream, byte); // Get first 2 I-frames if(byte == 0) { mpeg3video_get_firstframe(video); mpeg3video_read_frame_backend(video, 0); } video->repeat_count = 0; mpeg3video_drop_frames(video, frame_number - video->framenum); break; } } } else { video->repeat_count = 0; mpeg3video_drop_frames(video, frame_number - video->framenum); } } else /* Discontinue support of seeking without table of contents */ { mpeg3video_toc_error(); } #if 0 /* Seek to start of file */ if(frame_number < 16) { video->repeat_count = video->current_repeat = 0; mpeg3bits_seek_start(vstream); video->framenum = 0; result = mpeg3video_drop_frames(video, frame_number - video->framenum); } else { /* Seek to an I frame. */ //printf(__FUNCTION__ " frame_number=%d video->framenum=%d\n", frame_number, video->framenum); if((frame_number < video->framenum || frame_number - video->framenum > MPEG3_SEEK_THRESHOLD)) { /* Elementary stream. Estimate frame position from total bytes. */ if(file->is_video_stream) { int64_t byte = (int64_t)((double)(mpeg3demux_movie_size(demuxer) / track->total_frames) * frame_number); long minimum = 65535; int done = 0; /* Get GOP just before frame */ do { result = mpeg3bits_seek_byte(vstream, byte); mpeg3bits_start_reverse(vstream); if(!result) result = mpeg3video_prev_code(vstream, MPEG3_GOP_START_CODE); mpeg3bits_start_forward(vstream); mpeg3bits_getbits(vstream, 8); if(!result) result = mpeg3video_getgophdr(video); this_gop_start = mpeg3video_goptimecode_to_frame(video); //printf("wanted %ld guessed %ld byte %ld result %d\n", frame_number, this_gop_start, byte, result); if(labs(this_gop_start - frame_number) >= labs(minimum)) done = 1; else { minimum = this_gop_start - frame_number; byte += (long)((float)(frame_number - this_gop_start) * (double)(mpeg3demux_movie_size(demuxer) / track->total_frames)); if(byte < 0) byte = 0; } }while(!result && !done); //printf("wanted %d guessed %d\n", frame_number, this_gop_start); if(!result) { video->framenum = this_gop_start; result = mpeg3video_drop_frames(video, frame_number - video->framenum); } } else /* System stream */ { mpeg3bits_seek_time(vstream, (double)frame_number / video->frame_rate); byte = mpeg3bits_tell(vstream); mpeg3bits_start_reverse(vstream); mpeg3video_prev_code(vstream, MPEG3_GOP_START_CODE); mpeg3bits_getbits_reverse(vstream, 32); mpeg3bits_start_forward(vstream); while(!result && mpeg3bits_tell(vstream) < byte) { result = mpeg3video_read_frame_backend(video, 0); if(match_refframes) mpeg3video_match_refframes(video); match_refframes = 0; } //printf("seek system 3 %f\n", (double)frame_number / video->frame_rate); } video->framenum = frame_number; } else // Drop frames { mpeg3video_drop_frames(video, frame_number - video->framenum); } } #endif mpeg3demux_reset_pts(demuxer); } return result; } int mpeg3video_previous_frame(mpeg3video_t *video) { mpeg3_bits_t *bitstream = video->vstream; mpeg3_demuxer_t *demuxer = bitstream->demuxer; int result = 0; int64_t target_byte = 0; if(mpeg3demux_tell_byte(demuxer) <= 0) return 1; // Get location of end of previous picture mpeg3demux_start_reverse(demuxer); result = mpeg3video_prev_code(demuxer, MPEG3_PICTURE_START_CODE); if(!result) result = mpeg3video_prev_code(demuxer, MPEG3_PICTURE_START_CODE); if(!result) result = mpeg3video_prev_code(demuxer, MPEG3_PICTURE_START_CODE); if(!result) target_byte = mpeg3demux_tell_byte(demuxer); // Rewind 2 I-frames if(!result) { if(video->has_gops) result = mpeg3video_prev_code(demuxer, MPEG3_GOP_START_CODE); else result = mpeg3video_prev_code(demuxer, MPEG3_SEQUENCE_START_CODE); } if(!result) { if(video->has_gops) result = mpeg3video_prev_code(demuxer, MPEG3_GOP_START_CODE); else result = mpeg3video_prev_code(demuxer, MPEG3_SEQUENCE_START_CODE); } mpeg3demux_start_forward(demuxer); mpeg3bits_reset(bitstream); // Read up to correct byte result = 0; video->repeat_count = 0; while(!result && !mpeg3demux_eof(demuxer) && mpeg3demux_tell_byte(demuxer) < target_byte) { result = mpeg3video_read_frame_backend(video, 0); } video->repeat_count = 0; return 0; } int mpeg3video_drop_frames(mpeg3video_t *video, long frames) { int result = 0; long frame_number = video->framenum + frames; //printf("mpeg3video_drop_frames 1 %d %d\n", frame_number, video->framenum); /* Read the selected number of frames and skip b-frames */ while(!result && frame_number > video->framenum) { result = mpeg3video_read_frame_backend(video, frame_number - video->framenum); } //printf("mpeg3video_drop_frames 100\n"); return result; } libmpeg3-1.5.4/video/slice.c0000644000175000017500000004451207742725646016041 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include #include #define CLIP(x) ((x) >= 0 ? ((x) < 255 ? (x) : 255) : 0) static unsigned long long MMX_128 = 0x80008000800080LL; int mpeg3_new_slice_buffer(mpeg3_slice_buffer_t *slice_buffer) { pthread_mutexattr_t mutex_attr; slice_buffer->data = malloc(1024); slice_buffer->buffer_size = 0; slice_buffer->buffer_allocation = 1024; slice_buffer->current_position = 0; slice_buffer->bits_size = 0; slice_buffer->bits = 0; slice_buffer->done = 0; pthread_mutexattr_init(&mutex_attr); // pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ADAPTIVE_NP); pthread_mutex_init(&(slice_buffer->completion_lock), &mutex_attr); return 0; } int mpeg3_delete_slice_buffer(mpeg3_slice_buffer_t *slice_buffer) { free(slice_buffer->data); pthread_mutex_destroy(&(slice_buffer->completion_lock)); return 0; } int mpeg3_expand_slice_buffer(mpeg3_slice_buffer_t *slice_buffer) { int i; unsigned char *new_buffer = malloc(slice_buffer->buffer_allocation * 2); for(i = 0; i < slice_buffer->buffer_size; i++) new_buffer[i] = slice_buffer->data[i]; free(slice_buffer->data); slice_buffer->data = new_buffer; slice_buffer->buffer_allocation *= 2; return 0; } /* limit coefficients to -2048..2047 */ /* move/add 8x8-Block from block[comp] to refframe */ static inline int mpeg3video_addblock(mpeg3_slice_t *slice, mpeg3video_t *video, int comp, int bx, int by, int dct_type, int addflag) { int cc, i, iincr; unsigned char *rfp; short *bp; int spar = slice->sparse[comp]; /* color component index */ cc = (comp < 4) ? 0 : (comp & 1) + 1; if(cc == 0) { /* luminance */ if(video->pict_struct == FRAME_PICTURE) { if(dct_type) { /* field DCT coding */ rfp = video->newframe[0] + video->coded_picture_width * (by + ((comp & 2) >> 1)) + bx + ((comp & 1) << 3); iincr = (video->coded_picture_width << 1); } else { /* frame DCT coding */ rfp = video->newframe[0] + video->coded_picture_width * (by + ((comp & 2) << 2)) + bx + ((comp & 1) << 3); iincr = video->coded_picture_width; } } else { /* field picture */ rfp = video->newframe[0] + (video->coded_picture_width << 1) * (by + ((comp & 2) << 2)) + bx + ((comp & 1) << 3); iincr = (video->coded_picture_width << 1); } } else { /* chrominance */ /* scale coordinates */ if(video->chroma_format != CHROMA444) bx >>= 1; if(video->chroma_format == CHROMA420) by >>= 1; if(video->pict_struct == FRAME_PICTURE) { if(dct_type && (video->chroma_format != CHROMA420)) { /* field DCT coding */ rfp = video->newframe[cc] + video->chrom_width * (by + ((comp & 2) >> 1)) + bx + (comp & 8); iincr = (video->chrom_width << 1); } else { /* frame DCT coding */ rfp = video->newframe[cc] + video->chrom_width * (by + ((comp & 2) << 2)) + bx + (comp & 8); iincr = video->chrom_width; } } else { /* field picture */ rfp = video->newframe[cc] + (video->chrom_width << 1) * (by + ((comp & 2) << 2)) + bx + (comp & 8); iincr = (video->chrom_width << 1); } } bp = slice->block[comp]; if(addflag) { #ifdef HAVE_MMX if(video->have_mmx) { if(spar) { __asm__ __volatile__( "movq (%2), %%mm6\n" /* 4 blockvals */ "pxor %%mm4, %%mm4\n" "punpcklwd %%mm6, %%mm6\n" "punpcklwd %%mm6, %%mm6\n" ".align 8\n" "1:" "movq (%1), %%mm0\n" /* 8 rindex1 */ "movq %%mm0, %%mm2\n" "punpcklbw %%mm4, %%mm0\n" "punpckhbw %%mm4, %%mm2\n" "paddw %%mm6, %%mm0\n" "paddw %%mm6, %%mm2\n" "packuswb %%mm2, %%mm0\n" "movq %%mm0, (%1)\n" "leal (%1, %3), %1\n" "loop 1b\n" : /* scr dest */ : "c" (8),"r" (rfp), "r" (bp), "r" (iincr) ); } else { __asm__ __volatile__( "pxor %%mm4, %%mm4\n" ".align 8\n" "1:" "movq (%2), %%mm0\n" /* 8 rfp 0 1 2 3 4 5 6 7*/ "movq (%1), %%mm6\n" /* 4 blockvals 0 1 2 3 */ "movq %%mm0, %%mm2\n" "movq 8(%1), %%mm5\n" /* 4 blockvals 0 1 2 3 */ "punpcklbw %%mm4, %%mm0\n" /* 0 2 4 6 */ "punpckhbw %%mm4, %%mm2\n" /* 1 3 5 7 */ "paddw %%mm6, %%mm0\n" "paddw %%mm5, %%mm2\n" "packuswb %%mm2, %%mm0\n" "addl $16, %1\n" "movq %%mm0, (%2)\n" "leal (%2,%3), %2\n" "loop 1b\n" : /* scr dest */ : "c" (8),"r" (bp), "r" (rfp), "r" (iincr) ); } } else #endif for(i = 0; i < 8; i++) { rfp[0] = CLIP(bp[0] + rfp[0]); rfp[1] = CLIP(bp[1] + rfp[1]); rfp[2] = CLIP(bp[2] + rfp[2]); rfp[3] = CLIP(bp[3] + rfp[3]); rfp[4] = CLIP(bp[4] + rfp[4]); rfp[5] = CLIP(bp[5] + rfp[5]); rfp[6] = CLIP(bp[6] + rfp[6]); rfp[7] = CLIP(bp[7] + rfp[7]); rfp += iincr; bp += 8; } } else { #ifdef HAVE_MMX if(video->have_mmx) { if(spar) { __asm__ __volatile__( "movd (%2), %%mm0\n" /* " 0 0 0 v1" */ "punpcklwd %%mm0, %%mm0\n" /* " 0 0 v1 v1" */ "punpcklwd %%mm0, %%mm0\n" "paddw MMX_128, %%mm0\n" "packuswb %%mm0, %%mm0\n" "leal (%0,%1,2), %%eax\n" "movq %%mm0, (%0, %1)\n" "movq %%mm0, (%%eax)\n" "leal (%%eax,%1,2), %0\n" "movq %%mm0, (%%eax, %1)\n" "movq %%mm0, (%0)\n" "leal (%0,%1,2), %%eax\n" "movq %%mm0, (%0, %1)\n" "movq %%mm0, (%%eax)\n" "movq %%mm0, (%%eax, %1)\n" : : "D" (rfp), "c" (iincr), "b" (bp) : "eax"); } else { __asm__ __volatile__( "movq MMX_128,%%mm4\n" ".align 8\n" "1:" "movq (%1), %%mm0\n" "movq 8(%1), %%mm1\n" "paddw %%mm4, %%mm0\n" "movq 16(%1), %%mm2\n" "paddw %%mm4, %%mm1\n" "movq 24(%1), %%mm3\n" "paddw %%mm4, %%mm2\n" "packuswb %%mm1, %%mm0\n" "paddw %%mm4, %%mm3\n" "addl $32, %1\n" "packuswb %%mm3, %%mm2\n" "movq %%mm0, (%2)\n" "movq %%mm2, (%2,%3)\n" "leal (%2,%3,2), %2\n" "loop 1b\n" : : "c" (4), "r" (bp), "r" (rfp), "r" (iincr) ); } } else #endif for(i = 0; i < 8; i++) { rfp[0] = CLIP(bp[0] + 128); rfp[1] = CLIP(bp[1] + 128); rfp[2] = CLIP(bp[2] + 128); rfp[3] = CLIP(bp[3] + 128); rfp[4] = CLIP(bp[4] + 128); rfp[5] = CLIP(bp[5] + 128); rfp[6] = CLIP(bp[6] + 128); rfp[7] = CLIP(bp[7] + 128); rfp+= iincr; bp += 8; } } return 0; } int mpeg3_decode_slice(mpeg3_slice_t *slice) { mpeg3video_t *video = slice->video; int comp; int mb_type, cbp, motion_type = 0, dct_type; int macroblock_address, mba_inc, mba_max; int slice_vert_pos_ext; unsigned int code; int bx, by; int dc_dct_pred[3]; int mv_count, mv_format, mvscale; int pmv[2][2][2], mv_field_sel[2][2]; int dmv, dmvector[2]; int qs; int stwtype, stwclass; int snr_cbp; int i; mpeg3_slice_buffer_t *slice_buffer = slice->slice_buffer; /* number of macroblocks per picture */ mba_max = video->mb_width * video->mb_height; /* field picture has half as many macroblocks as frame */ if(video->pict_struct != FRAME_PICTURE) mba_max >>= 1; /* macroblock address */ macroblock_address = 0; /* first macroblock in slice is not skipped */ mba_inc = 0; slice->fault = 0; code = mpeg3slice_getbits(slice_buffer, 32); /* decode slice header (may change quant_scale) */ slice_vert_pos_ext = mpeg3video_getslicehdr(slice, video); /* reset all DC coefficient and motion vector predictors */ dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0; pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0; pmv[0][1][0] = pmv[0][1][1] = pmv[1][1][0] = pmv[1][1][1] = 0; for(i = 0; slice_buffer->current_position < slice_buffer->buffer_size; i++) { if(mba_inc == 0) { /* Done */ if(!mpeg3slice_showbits(slice_buffer, 23)) return 0; /* decode macroblock address increment */ mba_inc = mpeg3video_get_macroblock_address(slice); if(slice->fault) return 1; if(i == 0) { /* Get the macroblock_address */ macroblock_address = ((slice_vert_pos_ext << 7) + (code & 255) - 1) * video->mb_width + mba_inc - 1; /* first macroblock in slice: not skipped */ mba_inc = 1; } } if(slice->fault) return 1; if(macroblock_address >= mba_max) { /* mba_inc points beyond picture dimensions */ /*fprintf(stderr, "mpeg3_decode_slice: too many macroblocks in picture\n"); */ return 1; } /* not skipped */ if(mba_inc == 1) { mpeg3video_macroblock_modes(slice, video, &mb_type, &stwtype, &stwclass, &motion_type, &mv_count, &mv_format, &dmv, &mvscale, &dct_type); if(slice->fault) return 1; if(mb_type & MB_QUANT) { qs = mpeg3slice_getbits(slice_buffer, 5); if(video->mpeg2) slice->quant_scale = video->qscale_type ? mpeg3_non_linear_mquant_table[qs] : (qs << 1); else slice->quant_scale = qs; if(video->scalable_mode == SC_DP) /* make sure quant_scale is valid */ slice->quant_scale = slice->quant_scale; } /* motion vectors */ /* decode forward motion vectors */ if((mb_type & MB_FORWARD) || ((mb_type & MB_INTRA) && video->conceal_mv)) { if(video->mpeg2) mpeg3video_motion_vectors(slice, video, pmv, dmvector, mv_field_sel, 0, mv_count, mv_format, video->h_forw_r_size, video->v_forw_r_size, dmv, mvscale); else mpeg3video_motion_vector(slice, video, pmv[0][0], dmvector, video->forw_r_size, video->forw_r_size, 0, 0, video->full_forw); } if(slice->fault) return 1; /* decode backward motion vectors */ if(mb_type & MB_BACKWARD) { if(video->mpeg2) mpeg3video_motion_vectors(slice, video, pmv, dmvector, mv_field_sel, 1, mv_count, mv_format, video->h_back_r_size, video->v_back_r_size, 0, mvscale); else mpeg3video_motion_vector(slice, video, pmv[0][1], dmvector, video->back_r_size, video->back_r_size, 0, 0, video->full_back); } if(slice->fault) return 1; /* remove marker_bit */ if((mb_type & MB_INTRA) && video->conceal_mv) mpeg3slice_flushbit(slice_buffer); /* macroblock_pattern */ if(mb_type & MB_PATTERN) { cbp = mpeg3video_get_cbp(slice); if(video->chroma_format == CHROMA422) { /* coded_block_pattern_1 */ cbp = (cbp << 2) | mpeg3slice_getbits2(slice_buffer); } else if(video->chroma_format == CHROMA444) { /* coded_block_pattern_2 */ cbp = (cbp << 6) | mpeg3slice_getbits(slice_buffer, 6); } } else cbp = (mb_type & MB_INTRA) ? ((1 << video->blk_cnt) - 1) : 0; if(slice->fault) return 1; /* decode blocks */ mpeg3video_clearblock(slice, 0, video->blk_cnt); for(comp = 0; comp < video->blk_cnt; comp++) { if(cbp & (1 << (video->blk_cnt - comp - 1))) { if(mb_type & MB_INTRA) { if(video->mpeg2) mpeg3video_getmpg2intrablock(slice, video, comp, dc_dct_pred); else mpeg3video_getintrablock(slice, video, comp, dc_dct_pred); } else { if(video->mpeg2) mpeg3video_getmpg2interblock(slice, video, comp); else mpeg3video_getinterblock(slice, video, comp); } if(slice->fault) return 1; } } /* reset intra_dc predictors */ if(!(mb_type & MB_INTRA)) dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0; /* reset motion vector predictors */ if((mb_type & MB_INTRA) && !video->conceal_mv) { /* intra mb without concealment motion vectors */ pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0; pmv[0][1][0] = pmv[0][1][1] = pmv[1][1][0] = pmv[1][1][1] = 0; } if((video->pict_type == P_TYPE) && !(mb_type & (MB_FORWARD | MB_INTRA))) { /* non-intra mb without forward mv in a P picture */ pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0; /* derive motion_type */ if(video->pict_struct == FRAME_PICTURE) motion_type = MC_FRAME; else { motion_type = MC_FIELD; /* predict from field of same parity */ mv_field_sel[0][0] = (video->pict_struct == BOTTOM_FIELD); } } if(stwclass == 4) { /* purely spatially predicted macroblock */ pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0; pmv[0][1][0] = pmv[0][1][1] = pmv[1][1][0] = pmv[1][1][1] = 0; } } else { /* mba_inc!=1: skipped macroblock */ mpeg3video_clearblock(slice, 0, video->blk_cnt); /* reset intra_dc predictors */ dc_dct_pred[0] = dc_dct_pred[1] = dc_dct_pred[2] = 0; /* reset motion vector predictors */ if(video->pict_type == P_TYPE) pmv[0][0][0] = pmv[0][0][1] = pmv[1][0][0] = pmv[1][0][1] = 0; /* derive motion_type */ if(video->pict_struct == FRAME_PICTURE) motion_type = MC_FRAME; else { motion_type = MC_FIELD; /* predict from field of same parity */ mv_field_sel[0][0] = mv_field_sel[0][1] = (video->pict_struct == BOTTOM_FIELD); } /* skipped I are spatial-only predicted, */ /* skipped P and B are temporal-only predicted */ stwtype = (video->pict_type == I_TYPE) ? 8 : 0; /* clear MB_INTRA */ mb_type &= ~MB_INTRA; /* no block data */ cbp = 0; } snr_cbp = 0; /* pixel coordinates of top left corner of current macroblock */ bx = 16 * (macroblock_address % video->mb_width); by = 16 * (macroblock_address / video->mb_width); /* motion compensation */ if(!(mb_type & MB_INTRA)) mpeg3video_reconstruct(video, bx, by, mb_type, motion_type, pmv, mv_field_sel, dmvector, stwtype); /* copy or add block data into picture */ for(comp = 0; comp < video->blk_cnt; comp++) { if((cbp | snr_cbp) & (1 << (video->blk_cnt - 1 - comp))) { #ifdef HAVE_MMX if(video->have_mmx) IDCT_mmx(slice->block[comp]); else #endif mpeg3video_idct_conversion(slice->block[comp]); mpeg3video_addblock(slice, video, comp, bx, by, dct_type, (mb_type & MB_INTRA) == 0); } } /* advance to next macroblock */ macroblock_address++; mba_inc--; } return 0; } void mpeg3_slice_loop(mpeg3_slice_t *slice) { mpeg3video_t *video = slice->video; int result = 1; while(!slice->done) { pthread_mutex_lock(&(slice->input_lock)); if(!slice->done) { /* Get a buffer to decode */ result = 1; pthread_mutex_lock(&(video->slice_lock)); if(slice->buffer_step > 0) { while(slice->current_buffer <= slice->last_buffer) { if(!video->slice_buffers[slice->current_buffer].done && slice->current_buffer <= slice->last_buffer) { result = 0; break; } slice->current_buffer += slice->buffer_step; } } else { while(slice->current_buffer >= slice->last_buffer) { if(!video->slice_buffers[slice->current_buffer].done && slice->current_buffer >= slice->last_buffer) { result = 0; break; } slice->current_buffer += slice->buffer_step; } } /* Got one */ if(!result && slice->current_buffer >= 0 && slice->current_buffer < video->total_slice_buffers) { slice->slice_buffer = &(video->slice_buffers[slice->current_buffer]); slice->slice_buffer->done = 1; pthread_mutex_unlock(&(video->slice_lock)); pthread_mutex_unlock(&(slice->input_lock)); mpeg3_decode_slice(slice); pthread_mutex_unlock(&(slice->slice_buffer->completion_lock)); } else /* Finished with all */ { pthread_mutex_unlock(&(slice->completion_lock)); pthread_mutex_unlock(&(video->slice_lock)); } } pthread_mutex_unlock(&(slice->output_lock)); } } int mpeg3_new_slice_decoder(void *video, mpeg3_slice_t *slice) { pthread_attr_t attr; pthread_mutexattr_t mutex_attr; slice->video = video; slice->done = 0; pthread_mutexattr_init(&mutex_attr); // pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ADAPTIVE_NP); pthread_mutex_init(&(slice->input_lock), &mutex_attr); pthread_mutex_lock(&(slice->input_lock)); pthread_mutex_init(&(slice->output_lock), &mutex_attr); pthread_mutex_lock(&(slice->output_lock)); pthread_mutex_init(&(slice->completion_lock), &mutex_attr); pthread_mutex_lock(&(slice->completion_lock)); pthread_attr_init(&attr); pthread_create(&(slice->tid), &attr, (void*)mpeg3_slice_loop, slice); return 0; } int mpeg3_delete_slice_decoder(mpeg3_slice_t *slice) { slice->done = 1; pthread_mutex_unlock(&(slice->input_lock)); pthread_join(slice->tid, 0); pthread_mutex_destroy(&(slice->input_lock)); pthread_mutex_destroy(&(slice->output_lock)); return 0; } libmpeg3-1.5.4/video/slice.h0000644000175000017500000000012607742725646016037 0ustar enderender00000000000000#ifndef SLICE_H #define SLICE_H #include #include #endif libmpeg3-1.5.4/video/vlc.c0000644000175000017500000003551507742725646015531 0ustar enderender00000000000000#include "mpeg3private.h" #include "mpeg3protos.h" #include "vlc.h" /* variable length code tables */ /* Table B-3, mb_type in P-pictures, codes 001..1xx */ mpeg3_VLCtab_t mpeg3_PMBtab0[8] = { {ERROR,0}, {MB_FORWARD,3}, {MB_PATTERN,2}, {MB_PATTERN,2}, {MB_FORWARD|MB_PATTERN,1}, {MB_FORWARD|MB_PATTERN,1}, {MB_FORWARD|MB_PATTERN,1}, {MB_FORWARD|MB_PATTERN,1} }; /* Table B-3, mb_type in P-pictures, codes 000001..00011x */ mpeg3_VLCtab_t mpeg3_PMBtab1[8] = { {ERROR,0}, {MB_QUANT|MB_INTRA,6}, {MB_QUANT|MB_PATTERN,5}, {MB_QUANT|MB_PATTERN,5}, {MB_QUANT|MB_FORWARD|MB_PATTERN,5}, {MB_QUANT|MB_FORWARD|MB_PATTERN,5}, {MB_INTRA,5}, {MB_INTRA,5} }; /* Table B-4, mb_type in B-pictures, codes 0010..11xx */ mpeg3_VLCtab_t mpeg3_BMBtab0[16] = { {ERROR,0}, {ERROR,0}, {MB_FORWARD,4}, {MB_FORWARD|MB_PATTERN,4}, {MB_BACKWARD,3}, {MB_BACKWARD,3}, {MB_BACKWARD|MB_PATTERN,3}, {MB_BACKWARD|MB_PATTERN,3}, {MB_FORWARD|MB_BACKWARD,2}, {MB_FORWARD|MB_BACKWARD,2}, {MB_FORWARD|MB_BACKWARD,2}, {MB_FORWARD|MB_BACKWARD,2}, {MB_FORWARD|MB_BACKWARD|MB_PATTERN,2}, {MB_FORWARD|MB_BACKWARD|MB_PATTERN,2}, {MB_FORWARD|MB_BACKWARD|MB_PATTERN,2}, {MB_FORWARD|MB_BACKWARD|MB_PATTERN,2} }; /* Table B-4, mb_type in B-pictures, codes 000001..00011x */ mpeg3_VLCtab_t mpeg3_BMBtab1[8] = { {ERROR,0}, {MB_QUANT|MB_INTRA,6}, {MB_QUANT|MB_BACKWARD|MB_PATTERN,6}, {MB_QUANT|MB_FORWARD|MB_PATTERN,6}, {MB_QUANT|MB_FORWARD|MB_BACKWARD|MB_PATTERN,5}, {MB_QUANT|MB_FORWARD|MB_BACKWARD|MB_PATTERN,5}, {MB_INTRA,5}, {MB_INTRA,5} }; /* Table B-5, mb_type in spat. scal. I-pictures, codes 0001..1xxx */ mpeg3_VLCtab_t mpeg3_spIMBtab[16] = { {ERROR,0}, {MB_CLASS4,4}, {MB_QUANT|MB_INTRA,4}, {MB_INTRA,4}, {MB_CLASS4|MB_QUANT|MB_PATTERN,2}, {MB_CLASS4|MB_QUANT|MB_PATTERN,2}, {MB_CLASS4|MB_QUANT|MB_PATTERN,2}, {MB_CLASS4|MB_QUANT|MB_PATTERN,2}, {MB_CLASS4|MB_PATTERN,1}, {MB_CLASS4|MB_PATTERN,1}, {MB_CLASS4|MB_PATTERN,1}, {MB_CLASS4|MB_PATTERN,1}, {MB_CLASS4|MB_PATTERN,1}, {MB_CLASS4|MB_PATTERN,1}, {MB_CLASS4|MB_PATTERN,1}, {MB_CLASS4|MB_PATTERN,1} }; /* Table B-6, mb_type in spat. scal. P-pictures, codes 0010..11xx */ mpeg3_VLCtab_t mpeg3_spPMBtab0[16] = { {ERROR,0},{ERROR,0}, {MB_FORWARD,4}, {MB_WEIGHT|MB_FORWARD,4}, {MB_QUANT|MB_FORWARD|MB_PATTERN,3}, {MB_QUANT|MB_FORWARD|MB_PATTERN,3}, {MB_WEIGHT|MB_FORWARD|MB_PATTERN,3}, {MB_WEIGHT|MB_FORWARD|MB_PATTERN,3}, {MB_FORWARD|MB_PATTERN,2}, {MB_FORWARD|MB_PATTERN,2}, {MB_FORWARD|MB_PATTERN,2}, {MB_FORWARD|MB_PATTERN,2}, {MB_WEIGHT|MB_QUANT|MB_FORWARD|MB_PATTERN,2}, {MB_WEIGHT|MB_QUANT|MB_FORWARD|MB_PATTERN,2}, {MB_WEIGHT|MB_QUANT|MB_FORWARD|MB_PATTERN,2}, {MB_WEIGHT|MB_QUANT|MB_FORWARD|MB_PATTERN,2} }; /* Table B-6, mb_type in spat. scal. P-pictures, codes 0000010..000111x */ mpeg3_VLCtab_t mpeg3_spPMBtab1[16] = { {ERROR,0},{ERROR,0}, {MB_CLASS4|MB_QUANT|MB_PATTERN,7}, {MB_CLASS4,7}, {MB_PATTERN,7}, {MB_CLASS4|MB_PATTERN,7}, {MB_QUANT|MB_INTRA,7}, {MB_INTRA,7}, {MB_QUANT|MB_PATTERN,6}, {MB_QUANT|MB_PATTERN,6}, {MB_WEIGHT|MB_QUANT|MB_PATTERN,6}, {MB_WEIGHT|MB_QUANT|MB_PATTERN,6}, {MB_WEIGHT,6}, {MB_WEIGHT,6}, {MB_WEIGHT|MB_PATTERN,6}, {MB_WEIGHT|MB_PATTERN,6} }; /* Table B-7, mb_type in spat. scal. B-pictures, codes 0010..11xx */ mpeg3_VLCtab_t mpeg3_spBMBtab0[14] = { {MB_FORWARD,4}, {MB_FORWARD|MB_PATTERN,4}, {MB_BACKWARD,3}, {MB_BACKWARD,3}, {MB_BACKWARD|MB_PATTERN,3}, {MB_BACKWARD|MB_PATTERN,3}, {MB_FORWARD|MB_BACKWARD,2}, {MB_FORWARD|MB_BACKWARD,2}, {MB_FORWARD|MB_BACKWARD,2}, {MB_FORWARD|MB_BACKWARD,2}, {MB_FORWARD|MB_BACKWARD|MB_PATTERN,2}, {MB_FORWARD|MB_BACKWARD|MB_PATTERN,2}, {MB_FORWARD|MB_BACKWARD|MB_PATTERN,2}, {MB_FORWARD|MB_BACKWARD|MB_PATTERN,2} }; /* Table B-7, mb_type in spat. scal. B-pictures, codes 0000100..000111x */ mpeg3_VLCtab_t mpeg3_spBMBtab1[12] = { {MB_QUANT|MB_FORWARD|MB_PATTERN,7}, {MB_QUANT|MB_BACKWARD|MB_PATTERN,7}, {MB_INTRA,7}, {MB_QUANT|MB_FORWARD|MB_BACKWARD|MB_PATTERN,7}, {MB_WEIGHT|MB_FORWARD,6}, {MB_WEIGHT|MB_FORWARD,6}, {MB_WEIGHT|MB_FORWARD|MB_PATTERN,6}, {MB_WEIGHT|MB_FORWARD|MB_PATTERN,6}, {MB_WEIGHT|MB_BACKWARD,6}, {MB_WEIGHT|MB_BACKWARD,6}, {MB_WEIGHT|MB_BACKWARD|MB_PATTERN,6}, {MB_WEIGHT|MB_BACKWARD|MB_PATTERN,6} }; /* Table B-7, mb_type in spat. scal. B-pictures, codes 00000100x..000001111 */ mpeg3_VLCtab_t mpeg3_spBMBtab2[8] = { {MB_QUANT|MB_INTRA,8}, {MB_QUANT|MB_INTRA,8}, {MB_WEIGHT|MB_QUANT|MB_FORWARD|MB_PATTERN,8}, {MB_WEIGHT|MB_QUANT|MB_FORWARD|MB_PATTERN,8}, {MB_WEIGHT|MB_QUANT|MB_BACKWARD|MB_PATTERN,9}, {MB_CLASS4|MB_QUANT|MB_PATTERN,9}, {MB_CLASS4,9}, {MB_CLASS4|MB_PATTERN,9} }; /* Table B-8, mb_type in spat. scal. B-pictures, codes 001..1xx */ mpeg3_VLCtab_t mpeg3_SNRMBtab[8] = { {ERROR,0}, {0,3}, {MB_QUANT|MB_PATTERN,2}, {MB_QUANT|MB_PATTERN,2}, {MB_PATTERN,1}, {MB_PATTERN,1}, {MB_PATTERN,1}, {MB_PATTERN,1} }; /* Table B-10, motion_code, codes 0001 ... 01xx */ mpeg3_VLCtab_t mpeg3_MVtab0[8] = { {ERROR,0}, {3,3}, {2,2}, {2,2}, {1,1}, {1,1}, {1,1}, {1,1} }; /* Table B-10, motion_code, codes 0000011 ... 000011x */ mpeg3_VLCtab_t mpeg3_MVtab1[8] = { {ERROR,0}, {ERROR,0}, {ERROR,0}, {7,6}, {6,6}, {5,6}, {4,5}, {4,5} }; /* Table B-10, motion_code, codes 0000001100 ... 000001011x */ mpeg3_VLCtab_t mpeg3_MVtab2[12] = { {16,9}, {15,9}, {14,9}, {13,9}, {12,9}, {11,9}, {10,8}, {10,8}, {9,8}, {9,8}, {8,8}, {8,8} }; /* Table B-9, coded_block_pattern, codes 01000 ... 111xx */ mpeg3_VLCtab_t mpeg3_CBPtab0[32] = { {ERROR,0}, {ERROR,0}, {ERROR,0}, {ERROR,0}, {ERROR,0}, {ERROR,0}, {ERROR,0}, {ERROR,0}, {62,5}, {2,5}, {61,5}, {1,5}, {56,5}, {52,5}, {44,5}, {28,5}, {40,5}, {20,5}, {48,5}, {12,5}, {32,4}, {32,4}, {16,4}, {16,4}, {8,4}, {8,4}, {4,4}, {4,4}, {60,3}, {60,3}, {60,3}, {60,3} }; /* Table B-9, coded_block_pattern, codes 00000100 ... 001111xx */ mpeg3_VLCtab_t mpeg3_CBPtab1[64] = { {ERROR,0}, {ERROR,0}, {ERROR,0}, {ERROR,0}, {58,8}, {54,8}, {46,8}, {30,8}, {57,8}, {53,8}, {45,8}, {29,8}, {38,8}, {26,8}, {37,8}, {25,8}, {43,8}, {23,8}, {51,8}, {15,8}, {42,8}, {22,8}, {50,8}, {14,8}, {41,8}, {21,8}, {49,8}, {13,8}, {35,8}, {19,8}, {11,8}, {7,8}, {34,7}, {34,7}, {18,7}, {18,7}, {10,7}, {10,7}, {6,7}, {6,7}, {33,7}, {33,7}, {17,7}, {17,7}, {9,7}, {9,7}, {5,7}, {5,7}, {63,6}, {63,6}, {63,6}, {63,6}, {3,6}, {3,6}, {3,6}, {3,6}, {36,6}, {36,6}, {36,6}, {36,6}, {24,6}, {24,6}, {24,6}, {24,6} }; /* Table B-9, coded_block_pattern, codes 000000001 ... 000000111 */ mpeg3_VLCtab_t mpeg3_CBPtab2[8] = { {ERROR,0}, {0,9}, {39,9}, {27,9}, {59,9}, {55,9}, {47,9}, {31,9} }; /* Table B-1, macroblock_address_increment, codes 00010 ... 011xx */ mpeg3_VLCtab_t mpeg3_MBAtab1[16] = { {ERROR,0}, {ERROR,0}, {7,5}, {6,5}, {5,4}, {5,4}, {4,4}, {4,4}, {3,3}, {3,3}, {3,3}, {3,3}, {2,3}, {2,3}, {2,3}, {2,3} }; /* Table B-1, macroblock_address_increment, codes 00000011000 ... 0000111xxxx */ mpeg3_VLCtab_t mpeg3_MBAtab2[104] = { {33,11}, {32,11}, {31,11}, {30,11}, {29,11}, {28,11}, {27,11}, {26,11}, {25,11}, {24,11}, {23,11}, {22,11}, {21,10}, {21,10}, {20,10}, {20,10}, {19,10}, {19,10}, {18,10}, {18,10}, {17,10}, {17,10}, {16,10}, {16,10}, {15,8}, {15,8}, {15,8}, {15,8}, {15,8}, {15,8}, {15,8}, {15,8}, {14,8}, {14,8}, {14,8}, {14,8}, {14,8}, {14,8}, {14,8}, {14,8}, {13,8}, {13,8}, {13,8}, {13,8}, {13,8}, {13,8}, {13,8}, {13,8}, {12,8}, {12,8}, {12,8}, {12,8}, {12,8}, {12,8}, {12,8}, {12,8}, {11,8}, {11,8}, {11,8}, {11,8}, {11,8}, {11,8}, {11,8}, {11,8}, {10,8}, {10,8}, {10,8}, {10,8}, {10,8}, {10,8}, {10,8}, {10,8}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {9,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7}, {8,7} }; /* Table B-12, dct_dc_size_luminance, codes 00xxx ... 11110 */ mpeg3_VLCtab_t mpeg3_DClumtab0[32] = { {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {0, 3}, {0, 3}, {0, 3}, {0, 3}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 4}, {5, 4}, {6, 5}, {ERROR, 0} }; /* Table B-12, dct_dc_size_luminance, codes 111110xxx ... 111111111 */ mpeg3_VLCtab_t mpeg3_DClumtab1[16] = { {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {7, 6}, {8, 7}, {8, 7}, {8, 7}, {8, 7}, {9, 8}, {9, 8}, {10,9}, {11,9} }; /* Table B-13, dct_dc_size_chrominance, codes 00xxx ... 11110 */ mpeg3_VLCtab_t mpeg3_DCchromtab0[32] = { {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {0, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {1, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {3, 3}, {3, 3}, {3, 3}, {3, 3}, {4, 4}, {4, 4}, {5, 5}, {ERROR, 0} }; /* Table B-13, dct_dc_size_chrominance, codes 111110xxxx ... 1111111111 */ mpeg3_VLCtab_t mpeg3_DCchromtab1[32] = { {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {6, 6}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {7, 7}, {8, 8}, {8, 8}, {8, 8}, {8, 8}, {9, 9}, {9, 9}, {10,10}, {11,10} }; /* Table B-14, DCT coefficients table zero, * codes 0100 ... 1xxx (used for first (DC) coefficient) */ mpeg3_DCTtab_t mpeg3_DCTtabfirst[12] = { {0,2,4}, {2,1,4}, {1,1,3}, {1,1,3}, {0,1,1}, {0,1,1}, {0,1,1}, {0,1,1}, {0,1,1}, {0,1,1}, {0,1,1}, {0,1,1} }; /* Table B-14, DCT coefficients table zero, * codes 0100 ... 1xxx (used for all other coefficients) */ mpeg3_DCTtab_t mpeg3_DCTtabnext[12] = { {0,2,4}, {2,1,4}, {1,1,3}, {1,1,3}, {64,0,2}, {64,0,2}, {64,0,2}, {64,0,2}, /* EOB */ {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2} }; /* Table B-14, DCT coefficients table zero, * codes 000001xx ... 00111xxx */ mpeg3_DCTtab_t mpeg3_DCTtab0[60] = { {65,0,6}, {65,0,6}, {65,0,6}, {65,0,6}, /* Escape */ {2,2,7}, {2,2,7}, {9,1,7}, {9,1,7}, {0,4,7}, {0,4,7}, {8,1,7}, {8,1,7}, {7,1,6}, {7,1,6}, {7,1,6}, {7,1,6}, {6,1,6}, {6,1,6}, {6,1,6}, {6,1,6}, {1,2,6}, {1,2,6}, {1,2,6}, {1,2,6}, {5,1,6}, {5,1,6}, {5,1,6}, {5,1,6}, {13,1,8}, {0,6,8}, {12,1,8}, {11,1,8}, {3,2,8}, {1,3,8}, {0,5,8}, {10,1,8}, {0,3,5}, {0,3,5}, {0,3,5}, {0,3,5}, {0,3,5}, {0,3,5}, {0,3,5}, {0,3,5}, {4,1,5}, {4,1,5}, {4,1,5}, {4,1,5}, {4,1,5}, {4,1,5}, {4,1,5}, {4,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5} }; /* Table B-15, DCT coefficients table one, * codes 000001xx ... 11111111 */ mpeg3_DCTtab_t mpeg3_DCTtab0a[252] = { {65,0,6}, {65,0,6}, {65,0,6}, {65,0,6}, /* Escape */ {7,1,7}, {7,1,7}, {8,1,7}, {8,1,7}, {6,1,7}, {6,1,7}, {2,2,7}, {2,2,7}, {0,7,6}, {0,7,6}, {0,7,6}, {0,7,6}, {0,6,6}, {0,6,6}, {0,6,6}, {0,6,6}, {4,1,6}, {4,1,6}, {4,1,6}, {4,1,6}, {5,1,6}, {5,1,6}, {5,1,6}, {5,1,6}, {1,5,8}, {11,1,8}, {0,11,8}, {0,10,8}, {13,1,8}, {12,1,8}, {3,2,8}, {1,4,8}, {2,1,5}, {2,1,5}, {2,1,5}, {2,1,5}, {2,1,5}, {2,1,5}, {2,1,5}, {2,1,5}, {1,2,5}, {1,2,5}, {1,2,5}, {1,2,5}, {1,2,5}, {1,2,5}, {1,2,5}, {1,2,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {3,1,5}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {1,1,3}, {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, /* EOB */ {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, {64,0,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,3,4}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,1,2}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,2,3}, {0,4,5}, {0,4,5}, {0,4,5}, {0,4,5}, {0,4,5}, {0,4,5}, {0,4,5}, {0,4,5}, {0,5,5}, {0,5,5}, {0,5,5}, {0,5,5}, {0,5,5}, {0,5,5}, {0,5,5}, {0,5,5}, {9,1,7}, {9,1,7}, {1,3,7}, {1,3,7}, {10,1,7}, {10,1,7}, {0,8,7}, {0,8,7}, {0,9,7}, {0,9,7}, {0,12,8}, {0,13,8}, {2,3,8}, {4,2,8}, {0,14,8}, {0,15,8} }; /* Table B-14, DCT coefficients table zero, * codes 0000001000 ... 0000001111 */ mpeg3_DCTtab_t mpeg3_DCTtab1[8] = { {16,1,10}, {5,2,10}, {0,7,10}, {2,3,10}, {1,4,10}, {15,1,10}, {14,1,10}, {4,2,10} }; /* Table B-15, DCT coefficients table one, * codes 000000100x ... 000000111x */ mpeg3_DCTtab_t mpeg3_DCTtab1a[8] = { {5,2,9}, {5,2,9}, {14,1,9}, {14,1,9}, {2,4,10}, {16,1,10}, {15,1,9}, {15,1,9} }; /* Table B-14/15, DCT coefficients table zero / one, * codes 000000010000 ... 000000011111 */ mpeg3_DCTtab_t mpeg3_DCTtab2[16] = { {0,11,12}, {8,2,12}, {4,3,12}, {0,10,12}, {2,4,12}, {7,2,12}, {21,1,12}, {20,1,12}, {0,9,12}, {19,1,12}, {18,1,12}, {1,5,12}, {3,3,12}, {0,8,12}, {6,2,12}, {17,1,12} }; /* Table B-14/15, DCT coefficients table zero / one, * codes 0000000010000 ... 0000000011111 */ mpeg3_DCTtab_t mpeg3_DCTtab3[16] = { {10,2,13}, {9,2,13}, {5,3,13}, {3,4,13}, {2,5,13}, {1,7,13}, {1,6,13}, {0,15,13}, {0,14,13}, {0,13,13}, {0,12,13}, {26,1,13}, {25,1,13}, {24,1,13}, {23,1,13}, {22,1,13} }; /* Table B-14/15, DCT coefficients table zero / one, * codes 00000000010000 ... 00000000011111 */ mpeg3_DCTtab_t mpeg3_DCTtab4[16] = { {0,31,14}, {0,30,14}, {0,29,14}, {0,28,14}, {0,27,14}, {0,26,14}, {0,25,14}, {0,24,14}, {0,23,14}, {0,22,14}, {0,21,14}, {0,20,14}, {0,19,14}, {0,18,14}, {0,17,14}, {0,16,14} }; /* Table B-14/15, DCT coefficients table zero / one, * codes 000000000010000 ... 000000000011111 */ mpeg3_DCTtab_t mpeg3_DCTtab5[16] = { {0,40,15}, {0,39,15}, {0,38,15}, {0,37,15}, {0,36,15}, {0,35,15}, {0,34,15}, {0,33,15}, {0,32,15}, {1,14,15}, {1,13,15}, {1,12,15}, {1,11,15}, {1,10,15}, {1,9,15}, {1,8,15} }; /* Table B-14/15, DCT coefficients table zero / one, * codes 0000000000010000 ... 0000000000011111 */ mpeg3_DCTtab_t mpeg3_DCTtab6[16] = { {1,18,16}, {1,17,16}, {1,16,16}, {1,15,16}, {6,3,16}, {16,2,16}, {15,2,16}, {14,2,16}, {13,2,16}, {12,2,16}, {11,2,16}, {31,1,16}, {30,1,16}, {29,1,16}, {28,1,16}, {27,1,16} }; libmpeg3-1.5.4/video/vlc.h0000644000175000017500000001036407742725646015531 0ustar enderender00000000000000#ifndef VLC_H #define VLC_H /* variable length code tables */ typedef struct { char val, len; } mpeg3_VLCtab_t; typedef struct { char run, level, len; } mpeg3_DCTtab_t; /* Added 03/38/96 by Alex de Jong : avoid IRIX GNU warning */ #ifdef ERROR #undef ERROR #define ERROR 99 #endif /* Table B-3, mb_type in P-pictures, codes 001..1xx */ extern mpeg3_VLCtab_t mpeg3_PMBtab0[8]; /* Table B-3, mb_type in P-pictures, codes 000001..00011x */ extern mpeg3_VLCtab_t mpeg3_PMBtab1[8]; /* Table B-4, mb_type in B-pictures, codes 0010..11xx */ extern mpeg3_VLCtab_t mpeg3_BMBtab0[16]; /* Table B-4, mb_type in B-pictures, codes 000001..00011x */ extern mpeg3_VLCtab_t mpeg3_BMBtab1[8]; /* Table B-5, mb_type in spat. scal. I-pictures, codes 0001..1xxx */ extern mpeg3_VLCtab_t mpeg3_spIMBtab[16]; /* Table B-6, mb_type in spat. scal. P-pictures, codes 0010..11xx */ extern mpeg3_VLCtab_t mpeg3_spPMBtab0[16]; /* Table B-6, mb_type in spat. scal. P-pictures, codes 0000010..000111x */ extern mpeg3_VLCtab_t mpeg3_spPMBtab1[16]; /* Table B-7, mb_type in spat. scal. B-pictures, codes 0010..11xx */ extern mpeg3_VLCtab_t mpeg3_spBMBtab0[14]; /* Table B-7, mb_type in spat. scal. B-pictures, codes 0000100..000111x */ extern mpeg3_VLCtab_t mpeg3_spBMBtab1[12]; /* Table B-7, mb_type in spat. scal. B-pictures, codes 00000100x..000001111 */ extern mpeg3_VLCtab_t mpeg3_spBMBtab2[8]; /* Table B-8, mb_type in spat. scal. B-pictures, codes 001..1xx */ extern mpeg3_VLCtab_t mpeg3_SNRMBtab[8]; /* Table B-10, motion_code, codes 0001 ... 01xx */ extern mpeg3_VLCtab_t mpeg3_MVtab0[8]; /* Table B-10, motion_code, codes 0000011 ... 000011x */ extern mpeg3_VLCtab_t mpeg3_MVtab1[8]; /* Table B-10, motion_code, codes 0000001100 ... 000001011x */ extern mpeg3_VLCtab_t mpeg3_MVtab2[12]; /* Table B-9, coded_block_pattern, codes 01000 ... 111xx */ extern mpeg3_VLCtab_t mpeg3_CBPtab0[32]; /* Table B-9, coded_block_pattern, codes 00000100 ... 001111xx */ extern mpeg3_VLCtab_t mpeg3_CBPtab1[64]; /* Table B-9, coded_block_pattern, codes 000000001 ... 000000111 */ extern mpeg3_VLCtab_t mpeg3_CBPtab2[8]; /* Table B-1, macroblock_address_increment, codes 00010 ... 011xx */ extern mpeg3_VLCtab_t mpeg3_MBAtab1[16]; /* Table B-1, macroblock_address_increment, codes 00000011000 ... 0000111xxxx */ extern mpeg3_VLCtab_t mpeg3_MBAtab2[104]; /* Table B-12, dct_dc_size_luminance, codes 00xxx ... 11110 */ extern mpeg3_VLCtab_t mpeg3_DClumtab0[32]; /* Table B-12, dct_dc_size_luminance, codes 111110xxx ... 111111111 */ extern mpeg3_VLCtab_t mpeg3_DClumtab1[16]; /* Table B-13, dct_dc_size_chrominance, codes 00xxx ... 11110 */ extern mpeg3_VLCtab_t mpeg3_DCchromtab0[32]; /* Table B-13, dct_dc_size_chrominance, codes 111110xxxx ... 1111111111 */ extern mpeg3_VLCtab_t mpeg3_DCchromtab1[32]; /* Table B-14, DCT coefficients table zero, * codes 0100 ... 1xxx (used for first (DC) coefficient) */ extern mpeg3_DCTtab_t mpeg3_DCTtabfirst[12]; /* Table B-14, DCT coefficients table zero, * codes 0100 ... 1xxx (used for all other coefficients) */ extern mpeg3_DCTtab_t mpeg3_DCTtabnext[12]; /* Table B-14, DCT coefficients table zero, * codes 000001xx ... 00111xxx */ extern mpeg3_DCTtab_t mpeg3_DCTtab0[60]; /* Table B-15, DCT coefficients table one, * codes 000001xx ... 11111111 */ extern mpeg3_DCTtab_t mpeg3_DCTtab0a[252]; /* Table B-14, DCT coefficients table zero, * codes 0000001000 ... 0000001111 */ extern mpeg3_DCTtab_t mpeg3_DCTtab1[8]; /* Table B-15, DCT coefficients table one, * codes 000000100x ... 000000111x */ extern mpeg3_DCTtab_t mpeg3_DCTtab1a[8]; /* Table B-14/15, DCT coefficients table zero / one, * codes 000000010000 ... 000000011111 */ extern mpeg3_DCTtab_t mpeg3_DCTtab2[16]; /* Table B-14/15, DCT coefficients table zero / one, * codes 0000000010000 ... 0000000011111 */ extern mpeg3_DCTtab_t mpeg3_DCTtab3[16]; /* Table B-14/15, DCT coefficients table zero / one, * codes 00000000010000 ... 00000000011111 */ extern mpeg3_DCTtab_t mpeg3_DCTtab4[16]; /* Table B-14/15, DCT coefficients table zero / one, * codes 000000000010000 ... 000000000011111 */ extern mpeg3_DCTtab_t mpeg3_DCTtab5[16]; /* Table B-14/15, DCT coefficients table zero / one, * codes 0000000000010000 ... 0000000000011111 */ extern mpeg3_DCTtab_t mpeg3_DCTtab6[16]; #endif libmpeg3-1.5.4/video/worksheet.c0000644000175000017500000000134607742725646016753 0ustar enderender00000000000000#include #include #include static long long mpeg3_MMX_601_Y_COEF = 0x0000004000400040; inline void mpeg3_601_mmx(unsigned long y, unsigned long *output) { asm(" /* Output will be 0x00rrggbb */ movd (%0), %%mm0; /* Load y 0x00000000000000yy */ /* pmullw mpeg3_MMX_601_Y_COEF, %%mm0; // Scale y 0x00000000000000yy */ psllw $6, %%mm0; /* Shift y coeffs 0x0000yyy0yyy0yyy0 */ movd %%mm0, (%1); /* Store output */ " : : "r" (&y), "r" (output)); } int main(int argc, char *argv[]) { unsigned char output[1024]; memset(output, 0, 1024); mpeg3_601_mmx(1, (unsigned long*)output); printf("%02x%02x\n", *(unsigned char*)&output[1], *(unsigned char*)&output[0]); } libmpeg3-1.5.4/workarounds.c0000644000175000017500000000056607742725645016212 0ustar enderender00000000000000// GCC 3.0 workarounds #include "mpeg3private.h" #include "mpeg3protos.h" int64_t mpeg3io_tell_gcc(mpeg3_fs_t *fs) { return fs->current_byte; } double mpeg3_add_double_gcc(double x, double y) { return x + y; } double mpeg3_divide_double_gcc(double x, double y) { return x / y; } int64_t mpeg3_total_bytes_gcc(mpeg3_title_t *title) { return title->total_bytes; } libmpeg3-1.5.4/workarounds.h0000644000175000017500000000006507742725645016211 0ustar enderender00000000000000#ifndef WORKAROUNDS_H #define WORKAROUNDS_H #endif