5 * Copyright (C) 2001 Monty
7 * This file is part of snatch2{wav,yuv}, for use with the MJPEG
10 * snatch2wav is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
15 * snatch2wav is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with GNU Make; see the file COPYING. If not, write to
22 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
27 /* Snatch files can consist of multiple depths, rates and channels.
28 The ideal choice is to resample the whole thing to one common
31 /* this isn't added into the lav tools because the audio/video sync
32 isn't premade. It has to be calculated from timestamps and
33 maintain an arbitrary sized buffer. */
42 double global_zerotime
=0.;
44 unsigned char *buftemp
;
51 /* audio resampling ripped from sox and simplified */
54 * Copyright 1991 Lance Norskog And Sundry Contributors
55 * This source code is freely redistributable and may be used for
56 * any purpose. This copyright notice must be maintained.
57 * Lance Norskog And Sundry Contributors are not responsible for
58 * the consequences of using this software.
62 * Various changes, bugfixes(?), increased precision, by Stan Brooks.
66 * Turned a horridly complex sixteen page module prone to roundoff creep
67 * into a simpler, easier to use four page program with no accumulated
83 #define Amask ((1<<La)-1)
85 static double rolloff
=0.80; /* roll-off frequency */
86 static double beta
=16; /* passband/stopband tuning magic */
109 /********************* on the fly audio resampling ******************/
111 #define IzeroEPSILON 1E-21
112 static double Izero(double x
){
113 double sum
, u
, halfx
, temp
;
119 temp
= halfx
/(double)n
;
124 } while (u
>= IzeroEPSILON
*sum
);
128 static void LpFilter(double *filter
,int n
,double roll
,double beta
,long m
){
131 /* Calculate filter coeffs: */
134 double x
=M_PI
*(double)i
/(double)(m
);
135 filter
[i
]=sin(x
*roll
)/x
;
138 if(beta
>2) { /* Apply Kaiser window to filter coeffs: */
139 double ibeta
= 1.0/Izero(beta
);
141 double x
=(double)i
/(double)n
;
142 filter
[i
]*=Izero(beta
*sqrt(1.-x
*x
))*ibeta
;
148 int makeFilter(double *filter
,long nwing
,double roll
,double beta
,long m
){
152 /* it does help accuracy a bit to have the window stop at
153 * a zero-crossing of the sinc function */
154 mwing
= floor((double)nwing
/(m
/roll
))*(m
/roll
)+0.5;
156 /* Design a Nuttall or Kaiser windowed Sinc low-pass filter */
157 LpFilter(filter
, mwing
, roll
, beta
, m
);
159 /* 'correct' the DC gain of the lowpass filter */
160 for (i
=m
; i
<mwing
; i
+=m
)
162 gain
= 2*gain
+ filter
[0]; /* DC gain of real coefficients */
165 for (i
=0; i
<mwing
; i
++)
167 for (;i
<=nwing
;i
++)filter
[i
] = 0;
173 static void resample_init(resample_t
*r
, long inputrate
, long outputrate
,
175 long nwing
= Nc
* (Nmult
/2+1) + 1;
176 memset(r
,0,sizeof(*r
));
179 r
->filter
= malloc(sizeof(*r
->filter
)*(nwing
+1));
180 makeFilter(r
->filter
, nwing
, rolloff
, beta
, Nc
);
184 r
->input_rate
=inputrate
;
185 r
->output_rate
=outputrate
;
186 r
->ratio
=r
->input_rate
/(double)r
->output_rate
;
187 r
->factor
=r
->output_rate
/(double)r
->input_rate
;
189 r
->del
=Np
; /* Fixed-point Filter sampling-time-increment */
190 if(r
->factor
<1.0)r
->del
=r
->factor
*Np
+0.5;
191 r
->m
=(nwing
<<La
)/r
->del
;
193 r
->buffersize
=(r
->m
+r
->input_rate
)*16;
195 r
->data
=calloc(r
->buffersize
,sizeof(*r
->data
));
198 r
->input_head
=r
->m
*2+1; /* this eliminates output delay at the cost of
199 introducing a small absolute time shift */
203 static void resample_clear(resample_t
*r
){
205 if(r
->filter
)free(r
->filter
);
206 if(r
->data
)free(r
->data
);
210 static double linear_product(const double *filter
, const double *data
,
211 long dir
, double t
, long del
, long m
){
212 const double f
= 1./(1<<La
);
214 long h
=t
*del
+ (m
-1)*del
; /* so double sum starts with smallest coef's */
220 /* filter coef, lower La bits by linear interpolation */
221 double coef
= filter
[hh
] + (filter
[hh
+1]-filter
[hh
]) * (h
&Amask
) * f
;
231 static void resample_in(resample_t
*r
,double in
){
232 if(r
->input_head
==r
->buffersize
){
234 memmove(r
->data
,r
->data
+r
->input_base
-r
->m
,
235 r
->buffersize
-r
->input_base
+r
->m
);
236 r
->input_head
+=r
->m
-r
->input_base
;
240 r
->data
[r
->input_head
]=in
;
244 static int resample_out(resample_t
*r
,double *out
){
245 double input_integer
;
246 double input_fraction
=modf(r
->output_position
*r
->ratio
,&input_integer
);
247 long offset
=r
->input_base
+(int)input_integer
;
249 if(offset
+r
->m
+1>=r
->input_head
)
255 double *data
=r
->data
+offset
;
257 /* Past inner product: needs Np*Nmult in 31 bits */
258 v
=linear_product(r
->filter
,data
,-1,input_fraction
,r
->del
,r
->m
);
259 /* Future inner product: prefer even total */
260 v
+=linear_product(r
->filter
,data
+1,1,1.-input_fraction
,r
->del
,r
->m
);
262 if (r
->factor
<1.)v
*=r
->factor
;
265 r
->output_position
++;
266 if(r
->output_position
>=r
->output_rate
){
267 r
->output_position
=0;
268 r
->input_base
+=r
->input_rate
;
275 /****************** simple audio sample handling ****************/
278 long long audbuf_samples
; /* singluar samples, not pairs */
279 double audbuf_zerotime
;
280 int audbuf_head
; /* singluar samples, not pairs */
281 int audbuf_tail
; /* singluar samples, not pairs */
282 int audbuf_size
; /* singluar samples, not pairs */
286 long long samplesin
=0;
287 long long samplesout
=0;
288 long long samplesmissing
=0;
289 long long samplesdiscarded
=0;
291 static void buffer_sample(short v
,int nofakep
){
292 if(audbuf_head
>=audbuf_size
){
293 if(audbuf_tail
>audbuf_size
*3/4){
294 audbuf_head
-=audbuf_tail
;
296 memmove(audbuf
,audbuf
+audbuf_tail
,audbuf_head
*sizeof(*audbuf
));
302 audbuf
=realloc(audbuf
,audbuf_size
*sizeof(*audbuf
));
305 audbuf_size
=256*1024;
306 audbuf
=malloc(audbuf_size
*sizeof(*audbuf
));
309 audbuf
=malloc(audbuf_size
*sizeof(*audbuf
));
315 audbuf
[audbuf_head
]=v
;
321 static void lebuffer_sample(short v
,int nofakep
){
322 #ifdef __BIG_ENDIAN__
323 buffer_sample(((v
<<8)&0xff00) | ((v
>>8)&0xff),nofakep
);
325 buffer_sample(v
,nofakep
);
329 static void rebuffer_sample(long pos
,int nofakep
){
331 if(nofakep
)v
=audbuf
[audbuf_head
+pos
];
332 buffer_sample(v
,nofakep
);
335 static int convert_input(unsigned char *buf
,int fmt
,int *v
){
338 *v
=((int)buf
[0]-128)<<8;
341 *v
=(buf
[0]&0xff) | (((signed char *)buf
)[1]<<8);
344 *v
=(buf
[1]&0xff) | (((signed char *)buf
)[0]<<8);
347 *v
=((signed char *)buf
)[0]<<8;
350 *v
=(int)((buf
[0]&0xff)|((buf
[1]<<8)&0xff00))-32768;
353 *v
=(int)((buf
[1]&0xff)|((buf
[0]<<8)&0xff00))-32768;
360 static void pre_buffer_audio(long samples
,int nofakep
){
361 long i
,c
=audbuf_head
-audbuf_tail
;
363 /* just to expand lazily */
364 for(i
=0;i
<samples
;i
++)
365 buffer_sample(0,nofakep
);
369 memmove(audbuf
+audbuf_tail
+samples
,audbuf
+audbuf_tail
,c
*sizeof(*audbuf
));
370 memset(audbuf
+audbuf_tail
,0,samples
*sizeof(*audbuf
));
374 static double snip_gap_cleanly(double now
,int audio
){
375 /* fudge the clock to zip through most/all of the gap or overlap */
377 if(audio
|| !audio_p
){
379 if(last_time
+2.<now
){
380 fudge_time
-=now
-last_time
-1.;
383 fudge_time
+=last_time
-now
;
387 return(now
+fudge_time
);
390 /************************ snatch parsing *********************/
392 static int read_snatch_header(FILE *f
){
394 int ret
=fread(buffer
,1,12,f
);
396 fprintf(stderr
,"Error reading header: %s\n",strerror(ferror(f
)));
400 fprintf(stderr
,"EOF when header expected!\n");
403 if(strncmp(buffer
,"SNATCH",6)){
404 fprintf(stderr
,"Input does not begin with a Snatch header!\n");
410 if(buffer
[6]=='A')audio_p
=1;
411 if(buffer
[7]=='V')video_p
=1;
414 memset(fpsgraph
,0,sizeof(fpsgraph
));
418 int read_snatch_frame_helper(FILE *f
,long length
,int verify
){
419 long toread
=length
-buftemphead
+buftemptail
+5;
422 if(toread
+buftemphead
>buftempsize
){
424 buftemp
=realloc(buftemp
,(toread
+buftemphead
)*sizeof(*buftemp
));
426 buftemp
=malloc((toread
+buftemphead
)*sizeof(*buftemp
));
430 if((long)fread(buftemp
+buftemphead
,1,toread
,f
)!=toread
)return(-1);
435 if(!strncmp(buftemp
+buftemptail
+length
,"AUDIO",5))return(length
);
436 if(!strncmp(buftemp
+buftemptail
+length
,"VIDEO",5))return(length
);
437 if(!strncmp(buftemp
+buftemptail
+length
,"YUV12",5))return(length
);
444 resample_t resampler
[2];
446 static int process_audio_frame(char *head
,FILE *f
,int track_or_process
){
448 long long nextsamplepos
=audbuf_samples
;
451 long a
=atoi(s
),b
,ch
,ra
,fmt
,length
;
473 if((ret
=read_snatch_frame_helper(f
,length
,1))!=length
)
476 if(global_zerotime
==0){
482 if(audbuf_rate
==0)audbuf_rate
=ra
;
483 if(audbuf_channels
==0)audbuf_channels
=ch
;
488 case 5:case 6:case 8:case 9:
492 samplesin
+=length
/(ch
*bps
);
499 /* do we have a large capture gap (eg>2s)? */
500 t
=snip_gap_cleanly(t
,1);
502 if(audbuf_zerotime
==0){
506 long long actualpos
=(t
-audbuf_zerotime
)*audbuf_rate
*audbuf_channels
+.5;
509 /* we do not nail conversion to a realtime clock when only audio
510 has been captured; Snatch may have faked the audio interface,
511 which decoupled playback from any clock */
515 //fprintf(stderr,"audio sample jitter: %ld [%ld:%ld]\n",
516 //(long)(nextsamplepos-actualpos),(long)nextsamplepos,(long)actualpos);
518 /* hold last sample through any gap, assuming a bit of
519 hysteresis. That also holds us through roundoff error (the
520 roundoff error does *not* creep frame to frame) */
521 if(audbuf_channels
>1){
522 for(i
=actualpos
-nextsamplepos
-12;i
>0;i
-=2){
523 rebuffer_sample(-2,track_or_process
);
524 rebuffer_sample(-2,track_or_process
);
526 //fprintf(stderr,".");
529 for(i
=actualpos
-nextsamplepos
-12;i
>0;i
--){
530 rebuffer_sample(-1,track_or_process
);
532 //fprintf(stderr,".");
536 /* discard samples if we're way too far ahead; only likely to
537 happen due to a fault or misuse of splicing */
538 if(nextsamplepos
-actualpos
>12){
539 /* if we're so far ahead more than 10% of the frame must
540 disappear, just discard, else compact things a bit by
543 fprintf(stderr
,"audio sync got way ahead; this case not currently handled\n");
550 if(audbuf_rate
!=ra
&& resampler
[0].input_rate
!=ra
){
551 /* set up resampling */
552 resample_clear(&resampler
[0]);
553 resample_clear(&resampler
[1]);
554 resample_init(&resampler
[0],ra
,audbuf_rate
,track_or_process
);
555 resample_init(&resampler
[1],ra
,audbuf_rate
,track_or_process
);
564 i
+=convert_input(buftemp
+buftemptail
+i
,fmt
,&ileft
);
566 left
=ileft
*3.0517578e-5;
569 i
+=convert_input(buftemp
+buftemptail
+i
,fmt
,&iright
);
570 right
=iright
*3.0517578e-5;
573 if(audbuf_channels
>1){
575 resample_in(&resampler
[0],left
);
576 resample_in(&resampler
[1],right
);
578 resample_in(&resampler
[0],left
);
583 resample_in(&resampler
[0],left
*.5);
585 resample_in(&resampler
[0],left
);
589 /* output is always S16LE */
591 int flag
=resample_out(&resampler
[0],&left
);
595 sleft
=left
*32767.+.5,sright
;
596 if(sleft
>32767)sleft
=32767;
597 if(sleft
<-32768)sleft
=-32768;
598 lebuffer_sample(sleft
,track_or_process
);
600 if(audbuf_channels
>1){
602 flag
=resample_out(&resampler
[1],&right
);
603 sright
=right
*32767.+.5;
604 if(sright
>32767)sright
=32767;
605 if(sright
<-32768)sright
=-32768;
606 lebuffer_sample(sright
,track_or_process
);
608 lebuffer_sample(sleft
,track_or_process
);
615 /* output is always S16LE */
621 i
+=convert_input(buftemp
+buftemptail
+i
,fmt
,&left
);
623 i
+=convert_input(buftemp
+buftemptail
+i
,fmt
,&right
);
625 lebuffer_sample(left
,track_or_process
);
626 if(audbuf_channels
>1){
628 lebuffer_sample(right
,track_or_process
);
630 lebuffer_sample(left
,track_or_process
);
638 /*********************** video manipulation ***********************/
640 /* planar YUV12 (4:2:0) */
641 void yuvscale(unsigned char *src
,int sw
,int sh
,
642 unsigned char *dst
,int dw
,int dh
,
645 int dxo
=(dw
-sw
)/4,sxo
=0;
646 int dyo
=(dh
-sh
)/4,syo
=0;
648 /* dirt simple for now. No scaling, just centering */
659 for(y
=0;y
<dyo
*2;y
++){
660 unsigned char *dptr
=dst
+y
*dw
;
665 for(y
=0;y
<sh
&& y
<dh
;y
++){
666 unsigned char *sptr
=src
+(y
+syo
*2)*sw
+sxo
*2;
667 unsigned char *dptr
=dst
+(y
+dyo
*2)*dw
;
670 for(x
=0;x
<sw
&& x
<dw
;x
++)
676 for(;y
<dh
-dyo
*2;y
++){
677 unsigned char *dptr
=dst
+(y
+dyo
*2)*dw
;
690 unsigned char *dptr
=dst
+y
*dw
;
695 for(y
=0;y
<sh
&& y
<dh
;y
++){
696 unsigned char *sptr
=src
+(y
+syo
)*sw
+sxo
;
697 unsigned char *dptr
=dst
+(y
+dyo
)*dw
;
700 for(x
=0;x
<sw
&& x
<dw
;x
++)
707 unsigned char *dptr
=dst
+(y
+dyo
)*dw
;
717 unsigned char *dptr
=dst
+y
*dw
;
722 for(y
=0;y
<sh
&& y
<dh
;y
++){
723 unsigned char *sptr
=src
+(y
+syo
)*sw
+sxo
;
724 unsigned char *dptr
=dst
+(y
+dyo
)*dw
;
727 for(x
=0;x
<sw
&& x
<dw
;x
++)
734 unsigned char *dptr
=dst
+(y
+dyo
)*dw
;
741 void rgbscale(unsigned char *rgb
,int sw
,int sh
,
742 unsigned char *dst
,int dw
,int dh
,
743 unsigned int w
, int h
){
747 unsigned char *y
=alloca(ih
*iw
*3/2);
748 unsigned char *u
=y
+ih
*iw
;
749 unsigned char *v
=u
+ih
*iw
/4;
751 int every
=0,other
=sw
*3,c4
=0,i
,j
;
752 unsigned char *ye
=y
,*yo
=y
+iw
;
758 yval
= rgb
[every
]*19595 + rgb
[every
+1]*38470 + rgb
[every
+2]*7471;
759 uval
= rgb
[every
+2]*65536 - rgb
[every
]*22117 - rgb
[every
+1]*43419;
760 vval
= rgb
[every
]*65536 - rgb
[every
+1]*54878 - rgb
[every
+2]*10658;
763 yval
= rgb
[every
]*19595 + rgb
[every
+1]*38470 + rgb
[every
+2]*7471;
764 uval
+= rgb
[every
+2]*65536 - rgb
[every
]*22117 - rgb
[every
+1]*43419;
765 vval
+= rgb
[every
]*65536 - rgb
[every
+1]*54878 - rgb
[every
+2]*10658;
769 yval
= rgb
[other
]*19595 + rgb
[other
+1]*38470 + rgb
[other
+2]*7471;
770 uval
= rgb
[other
+2]*65536 - rgb
[other
]*22117 - rgb
[other
+1]*43419;
771 vval
= rgb
[other
]*65536 - rgb
[other
+1]*54878 - rgb
[other
+2]*10658;
774 yval
= rgb
[other
]*19595 + rgb
[other
+1]*38470 + rgb
[other
+2]*7471;
775 uval
+= rgb
[other
+2]*65536 - rgb
[other
]*22117 - rgb
[other
+1]*43419;
776 vval
+= rgb
[other
]*65536 - rgb
[other
+1]*54878 - rgb
[other
+2]*10658;
780 u
[c4
] =(uval
>>19)+128;
781 v
[c4
++]=(vval
>>19)+128;
786 every
+=sw
*3 + sw
%2*3;
787 other
+=sw
*3 + sw
%2*3;
791 yuvscale(y
,iw
,ih
,dst
,dw
,dh
,w
,h
);
795 unsigned char **vidbuf
;
796 long long *vidbuf_frameno
;
797 double vidbuf_zerotime
;
798 long long vidbuf_frames
;
810 long long framesin
=0;
811 long long framesout
=0;
812 long long framesmissing
=0;
813 long long framesdiscarded
=0;
815 double video_last_time
=-1;
817 static int process_video_frame(char *buffer
,FILE *f
,int notfakep
,int yuvp
){
819 long a
=atoi(s
),b
,w
,h
,length
;
840 if((ret
=read_snatch_frame_helper(f
,length
,1))!=length
)
843 if(global_zerotime
==0){
849 if(t
<begin_time
)return(length
);
853 /* do we have a large capture gap (eg>2s)? */
854 t
=snip_gap_cleanly(t
,0);
856 if(video_last_time
!=-1){
857 double del_t
=t
-video_last_time
;
859 int val
=ceil(1./(t
-video_last_time
));
866 /* video sync is fundamentally different from audio. We assume that
867 frames never appear early; an frame that seems early in context
868 of the previous frame is due backlogged framebuffer catching up
869 and this frame is actually late, as are however many 'on time'
871 if(vidbuf_zerotime
==0.){
874 double ideal
=(double)vidbuf_frames
;
875 double actual
=(t
-vidbuf_zerotime
)*vidin_fps
;
876 double drift
=actual
-ideal
;
879 /* intentional range for hysteresis */
881 /* 'early' frame; bump the whole train back if possible,
883 if(vidbuf_head
-vidbuf_tail
<
884 vidbuf_frameno
[vidbuf_head
-1]+1-
885 vidbuf_frameno
[vidbuf_tail
]){
887 /* yes, there's a hole. look for it */
889 vidbuf_frameno
[vidbuf_head
-1]--;
890 for(i
=vidbuf_head
-1;i
>vidbuf_tail
;i
--){
891 if(vidbuf_frameno
[i
]==vidbuf_frameno
[i
-1])
892 vidbuf_frameno
[i
-1]--;
896 vidbuf_frames
=ideal
-1;
900 /* no room to bump back. Discard the 'early' frame
901 in order to reclaim sync, even if destructively. */
908 /* 'late' frame. Skip the counter ahead. Don't
909 carry forward through the gap yet. */
910 vidbuf_frames
=rint(actual
);
914 if(vidbuf_width
==0)vidbuf_width
=(w
>>1)<<1;
915 if(vidbuf_height
==0)vidbuf_height
=(h
>>1)<<1;
918 if(vidbuf_head
>=vidbuf_size
){
928 memmove(vidbuf
,vidbuf
+1,(vidbuf_size
-1)*sizeof(*vidbuf
));
929 vidbuf
[vidbuf_size
-1]=temp
;
931 memmove(vidbuf_frameno
,vidbuf_frameno
+1,
932 (vidbuf_size
-1)*sizeof(*vidbuf_frameno
));
937 if(notfakep
)vidbuf
=realloc(vidbuf
,vidbuf_size
*sizeof(*vidbuf
));
938 vidbuf_frameno
=realloc(vidbuf_frameno
,vidbuf_size
*sizeof(*vidbuf_frameno
));
941 vidbuf
=malloc(vidbuf_size
*sizeof(*vidbuf
));
942 vidbuf_frameno
=malloc(vidbuf_size
*sizeof(*vidbuf_frameno
));
945 vidbuf
[vidbuf_size
-1]=malloc(vidbuf_width
*vidbuf_height
*3/2);
948 vidbuf_frameno
[vidbuf_head
]=vidbuf_frames
;
951 /* scale image into buffer */
954 yuvscale(buftemp
+buftemptail
,w
,h
,vidbuf
[vidbuf_head
],vidbuf_width
,vidbuf_height
,
955 scale_width
,scale_height
);
957 rgbscale(buftemp
+buftemptail
,w
,h
,vidbuf
[vidbuf_head
],vidbuf_width
,vidbuf_height
,
958 scale_width
,scale_height
);
960 /* finally any needed invasive blanking */
967 static char *strrstr(char *string
,char *test
){
970 while((temp
=strstr(string
,test
))){
977 /* more complicated than it used to be; we need to check framing */
978 static int read_snatch_frame(FILE *f
,int wa
,int wv
){
981 memmove(buftemp
,buftemp
+buftemptail
,buftemphead
-buftemptail
);
982 buftemphead
-=buftemptail
;
986 if(!read_snatch_frame_helper(f
,2048,0))return(0);
989 unsigned char *poss
=memchr(buftemp
,':',buftemphead
);
991 if(poss
)pos
=poss
-buftemp
;
993 char *audio
,*video
,*yuv12
;
997 /* search *backwards* from the colon */
998 audio
=strrstr(buftemp
,"AUDIO");
999 video
=strrstr(buftemp
,"VIDEO");
1000 yuv12
=strrstr(buftemp
,"YUV12");
1004 if(audio
|| video
|| yuv12
){
1006 ret
=process_audio_frame(audio
, f
, wa
);
1008 ret
=process_video_frame(video
, f
, wv
,0);
1011 ret
=process_video_frame(yuv12
, f
, wv
,1);
1023 buftemptail
=buftemphead
-130;
1030 /* writes a wav header without the length set. This is also the 32
1031 bit WAV header variety... please please please let the mjpeg tools
1032 ignore the length... */
1033 void PutNumLE(long num
,FILE *f
,int bytes
){
1036 if(fputc((num
>>(i
<<3))&0xff,f
)==EOF
){
1037 fprintf(stderr
,"Unable to write output: %s\n",strerror(ferror(f
)));
1044 void WriteWav(FILE *f
,long channels
,long rate
,long bits
){
1046 PutNumLE(0x7fffffffUL
,f
,4);
1047 fprintf(f
,"WAVEfmt ");
1050 PutNumLE(channels
,f
,2);
1052 PutNumLE(rate
*channels
*((bits
-1)/8+1),f
,4);
1053 PutNumLE(((bits
-1)/8+1)*channels
,f
,2);
1056 PutNumLE(0x7fffffffUL
,f
,4);
1059 void WriteYuv(FILE *f
,int w
,int h
,int fpscode
){
1060 fprintf(f
,"YUV4MPEG %d %d %d\n",w
,h
,fpscode
);
1063 static int frameratesn
[]={
1064 0, 24000, 24, 25, 30000, 30, 50, 60000, 60 };
1065 static int frameratesd
[]={
1066 0., 1001, 1, 1, 1001, 1, 1, 1001, 1 };
1068 void WriteYuv2(FILE *f
,int w
,int h
,int fpscode
){
1069 fprintf(f
,"YUV4MPEG2 W%d H%d F%d:%d Ip A1:1\n",w
,h
,
1070 frameratesn
[fpscode
],frameratesd
[fpscode
]);
1073 /* YV12 aka 4:2:0 planar */
1074 void YUVout(unsigned char *buf
,FILE *f
){
1075 fprintf(f
,"FRAME\n");
1076 fwrite(buf
,1,vidbuf_width
*vidbuf_height
*3/2,f
);
1084 int video_timeahead
;
1086 int snatch_iterator(FILE *in
,FILE *out
,int process_audio
,int process_video
){
1088 if(read_snatch_header(in
)){
1090 if(process_audio
&& !audio_p
){
1091 fprintf(stderr
,"No audio in this stream\n");
1094 if(process_video
&& !video_p
){
1095 fprintf(stderr
,"No video in this stream\n");
1106 int ret
=read_snatch_frame(in
,process_audio
,process_video
);
1111 if(audio_p
&& video_p
){
1113 /* pad beginning of stream for sync */
1114 if(vidbuf_head
-vidbuf_tail
&& audbuf_head
-audbuf_tail
){
1115 double time_dif
=vidbuf_zerotime
-audbuf_zerotime
;
1122 WriteWav(out
,audbuf_channels
,audbuf_rate
,16);
1123 if(process_video
==2)
1124 WriteYuv2(out
,vidbuf_width
,vidbuf_height
,ratecode
);
1125 if(process_video
==1)
1126 WriteYuv(out
,vidbuf_width
,vidbuf_height
,ratecode
);
1130 /* we don't write frames/samples here; we queue new ones out
1131 ahead until everything's even */
1134 /* audio started first; prestretch video, then repad with
1136 frames
=ceil(time_dif
*vidin_fps
);
1137 time_dif
-=(frames
/vidin_fps
);
1138 vidbuf_zerotime
-=(frames
/vidin_fps
);
1139 for(i
=vidbuf_tail
+1;i
<vidbuf_head
;i
++)
1140 vidbuf_frameno
[i
]+=frames
;
1141 framesmissing
+=frames
;
1144 samples
= -time_dif
*audbuf_rate
;
1145 samplesmissing
+=samples
;
1147 pre_buffer_audio(samples
*audbuf_channels
,process_audio
);
1148 audbuf_zerotime
=vidbuf_zerotime
;
1153 /* that was short; either no vid or no audio */
1154 if(vidbuf_head
-vidbuf_tail
==0)
1155 fprintf(stderr
,"Audio/Video stream contained no video.\n");
1156 if(audbuf_head
-audbuf_tail
==0)
1157 fprintf(stderr
,"Audio/Video stream contained no audio.\n");
1166 WriteWav(out
,audbuf_channels
,audbuf_rate
,16);
1167 if(process_video
==2)
1168 WriteYuv2(out
,vidbuf_width
,vidbuf_height
,ratecode
);
1169 if(process_video
==1)
1170 WriteYuv(out
,vidbuf_width
,vidbuf_height
,ratecode
);
1178 /* write out all pending audio/video */
1181 for(i
=vidbuf_tail
;i
<vidbuf_head
;i
++){
1182 int oframes
=(i
+1<vidbuf_head
)?
1183 vidbuf_frameno
[i
+1]*vidout_fps
/vidin_fps
-
1184 vidbuf_frameno
[i
] *vidout_fps
/vidin_fps
:
1185 vidout_fps
/vidin_fps
;
1186 int iframes
=(i
+1<vidbuf_head
)?
1187 vidbuf_frameno
[i
+1]-
1192 framesmissing
+=iframes
-1;
1196 YUVout(vidbuf
[i
],out
);
1201 long samples
=audbuf_head
-audbuf_tail
;
1202 samplesout
+=samples
/audbuf_channels
;
1204 fwrite(audbuf
+audbuf_tail
,2,samples
,out
);
1209 if(video_p
&& process_video
){
1210 while(vidbuf_head
-vidbuf_tail
>video_timeahead
){
1212 vidbuf_frameno
[vidbuf_tail
+1]*vidout_fps
/vidin_fps
-
1213 vidbuf_frameno
[vidbuf_tail
] *vidout_fps
/vidin_fps
;
1215 vidbuf_frameno
[vidbuf_tail
+1]-
1216 vidbuf_frameno
[vidbuf_tail
] ;
1218 framesmissing
+=iframes
-1;
1222 YUVout(vidbuf
[vidbuf_tail
],out
);
1228 if(audio_p
&& process_audio
){
1229 if(audbuf_head
-audbuf_tail
){
1230 long samples
=audbuf_head
-audbuf_tail
;
1232 fwrite(audbuf
+audbuf_tail
,2,samples
,out
);
1233 samplesout
+=samples
/audbuf_channels
;
1234 audbuf_tail
+=samples
;