[xiph-commits] r18999 - trunk/y4oi
xiphmont at svn.xiph.org
xiphmont at svn.xiph.org
Sun Sep 15 18:48:08 PDT 2013
Author: xiphmont
Date: 2013-09-15 18:48:08 -0700 (Sun, 15 Sep 2013)
New Revision: 18999
Modified:
trunk/y4oi/main.c
trunk/y4oi/output.c
Log:
Add direct wav and y4m output
Modified: trunk/y4oi/main.c
===================================================================
--- trunk/y4oi/main.c 2013-09-16 01:46:20 UTC (rev 18998)
+++ trunk/y4oi/main.c 2013-09-16 01:48:08 UTC (rev 18999)
@@ -37,7 +37,7 @@
static int no_rewrite=0;
static int global_ended=0;
-const char *optstring = "b:c:e:f:F:ho:sSvqNi";
+const char *optstring = "b:c:e:f:F:ho:sSvqNiW:Y:";
struct option options [] = {
{"begin",required_argument,NULL,'b'},
{"cut",required_argument,NULL,'c'},
@@ -52,13 +52,15 @@
{"force-no-sync",no_argument,NULL,'S'},
{"quiet",no_argument,NULL,'q'},
{"verbose",required_argument,NULL,'v'},
+ {"wav",required_argument,NULL,'W'},
+ {"yuv",required_argument,NULL,'Y'},
{NULL,0,NULL,0}
};
void usage(FILE *out){
fprintf(out,
- "\ny4oi 20100222\n"
+ "\ny4oi 20131003\n"
"performs basic operations on yuv4ogg interchange streams in prep for\n"
"theora encoding\n\n"
@@ -86,19 +88,21 @@
" -N --no-rewrite : do not rewrite output PTS values. Retain\n"
" original PTS values even if input streams\n"
" were synchronized.\n"
- " -o --output FILE : output file/pipe (stdout default)\n"
+ " -o --output FILE : y4o output file/pipe (stdout default)\n"
" -q --quiet : completely silent operation\n"
" -s --force-sync : perform autosync even on streams marked as\n"
" already synchronized\n"
" -S --force-no-sync : do not perform stream sync even on unsynced\n"
" streams\n"
" -v --verbose : increase verbosity level by one\n"
+ " -W --wav FILE : output audio to FILE in wave format.\n"
+ " -Y --yuv FILE : output video to FILE in yuv4mpeg2 format.\n"
"\n"
- "VIDEO FILTERS/OPTIONS:\n"
+ /* "VIDEO FILTERS/OPTIONS:\n"
"\n"
"OUTPUT FILTERS/OPTIONS:\n"
" output : output y4o stream to a file or pipe.\n"
- " file=<value> . destination file; default is stdout\n\n"
+ " file=<value> . destination file; default is stdout\n\n"*/
);
}
@@ -776,6 +780,8 @@
int infiles=0,i;
char *outfile=NULL;
+ char *wavfile=NULL;
+ char *yuvfile=NULL;
int primary_video=-1;
int primary_audio=-1;
@@ -842,6 +848,16 @@
free(outfile);
outfile=strdup(optarg);
break;
+ case 'W':
+ if(wavfile)
+ free(wavfile);
+ wavfile=strdup(optarg);
+ break;
+ case 'Y':
+ if(yuvfile)
+ free(yuvfile);
+ yuvfile=strdup(optarg);
+ break;
default:
usage(stderr);
exit(1);
@@ -868,11 +884,10 @@
if(!filter_is_last_output()){
char *buffer=NULL;
/* add an implicit output filter */
- if(outfile){
- asprintf(&buffer,"output:file=%s",outfile);
- }else{
- asprintf(&buffer,"output");
- }
+ asprintf(&buffer,"output%s%s%s%s%s%s",
+ outfile?":file=":"", outfile?outfile:"",
+ wavfile?":wav=":"", wavfile?wavfile:"",
+ yuvfile?":yuv=":"", yuvfile?yuvfile:"");
if(filter_append(buffer)){
exit(1);
Modified: trunk/y4oi/output.c
===================================================================
--- trunk/y4oi/output.c 2013-09-16 01:46:20 UTC (rev 18998)
+++ trunk/y4oi/output.c 2013-09-16 01:48:08 UTC (rev 18999)
@@ -27,8 +27,18 @@
typedef struct {
char *filename;
+ char *wavfilename;
+ char *yuvfilename;
FILE *outfile;
+ FILE *wavfile;
+ int wavno;
+ FILE *yuvfile;
+ int yuvno;
int wrote_header;
+
+ size_t wavebytes;
+ int wavch;
+ int wavrate;
} internal;
static void parse_options(fq_t *queue){
@@ -50,6 +60,32 @@
yerror("Unable to open '%s' for output; %s\n",i->filename,strerror(errno));
exit(1);
}
+ }else if(!strcmp(*key,"wav")){
+ if(!*val){
+ yerror("No filename given for option 'wav'\n");
+ exit(1);
+ }
+ i->wavfilename=strdup(*val);
+ if(i->wavfile)
+ fclose(i->wavfile);
+ i->wavfile=fopen(i->wavfilename,"wb");
+ if(!i->wavfile){
+ yerror("Unable to open '%s' for output; %s\n",i->wavfilename,strerror(errno));
+ exit(1);
+ }
+ }else if(!strcmp(*key,"yuv")){
+ if(!*val){
+ yerror("No filename given for option 'yuv'\n");
+ exit(1);
+ }
+ i->yuvfilename=strdup(*val);
+ if(i->yuvfile)
+ fclose(i->yuvfile);
+ i->yuvfile=fopen(i->yuvfilename,"wb");
+ if(!i->yuvfile){
+ yerror("Unable to open '%s' for output; %s\n",i->yuvfilename,strerror(errno));
+ exit(1);
+ }
}else{
yerror("No such option '%s'\n",*key);
}
@@ -58,12 +94,65 @@
val++;
}
- if(!i->outfile){
+ if(!i->outfile && !i->wavfile && !i->yuvfile){
i->outfile=stdout;
i->filename=strdup("stdout");
}
}
+static void PutNumLE(long num,FILE *f,int bytes){
+ int i=0;
+ while(bytes--){
+ fputc((num>>(i<<3))&0xff,f);
+ i++;
+ }
+}
+
+static void waveheader(internal *i, size_t size){
+ if(size>0x7fffffff)size=0x7fffffff;
+ fprintf(i->wavfile,"RIFF");
+ PutNumLE(size+44-8,i->wavfile,4);
+ fprintf(i->wavfile,"WAVEfmt ");
+ PutNumLE(16,i->wavfile,4);
+ PutNumLE(1,i->wavfile,2);
+ PutNumLE(i->wavch,i->wavfile,2);
+ PutNumLE(i->wavrate,i->wavfile,4);
+ PutNumLE(i->wavrate*i->wavch*2,i->wavfile,4); /* always output 16 bit */
+ PutNumLE(i->wavch*2,i->wavfile,2); /* always output 16 bit */
+ PutNumLE(16,i->wavfile,2);
+ fprintf(i->wavfile,"data");
+ PutNumLE(size,i->wavfile,4);
+}
+
+/* equivalent pixel format strings in YUV4MPEG2 */
+char *translateformat1[]={
+ NULL,
+ NULL,
+ "420jpeg", //2 chroma sample is centered vertically and horizontally between luma samples
+ "420", //3 chroma sample is centered vertically between lines, cosited horizontally */
+ "420paldv", //4 chroma sample is cosited vertically and horizontally */
+ NULL,
+ NULL,
+ "422", //7 chroma sample is cosited horizontally */
+ NULL,
+ "444", //9
+ NULL
+};
+
+char *translateformat2[]={
+ NULL, // no fallback
+ NULL, // no fallback
+ "420jpeg",
+ "420",
+ "420paldv",
+ "420", // Use mpeg 420 as fallback
+ "422",
+ "422",
+ "422", // use mpeg 422 as a fallback
+ "444",
+ NULL
+};
+
/* the output filter needs to wait until it has seen parameter frames
from each stream before it can write an output header */
static void startup_header(fq_t *queue){
@@ -76,42 +165,122 @@
if(j==queue->streams){
- /* container header */
- fprintf(i->outfile,"YUV4OGG S%c\n", (queue->tail->synced ? 'n' : 'y'));
+ if(i->outfile){
+ /* container header */
+ fprintf(i->outfile,"YUV4OGG S%c\n", (queue->tail->synced ? 'n' : 'y'));
- /* stream headers */
- for(j=0;j<queue->streams;j++){
- /* find first stream of the given type */
- fq_frame_t *ptr = queue->tail;
- while(ptr && ptr->sno != j)
- ptr=ptr->next;
+ /* stream headers */
+ for(j=0;j<queue->streams;j++){
+ /* find first stream of the given type */
+ fq_frame_t *ptr = queue->tail;
+ while(ptr && ptr->sno != j)
+ ptr=ptr->next;
- if(!ptr){
- yerror("Output couldn't find stream number %d\n\n",j);
- exit(1);
+ if(!ptr){
+ yerror("Output couldn't find stream number %d\n\n",j);
+ exit(1);
+ }
+
+ switch(ptr->st){
+ case STREAM_AUDIO:
+ fprintf(i->outfile,"AUDIO R%d C%d\n",
+ ptr->sp.audio.rate,ptr->sp.audio.ch);
+ break;
+ case STREAM_VIDEO:
+ fprintf(i->outfile,"VIDEO W%d H%d F%d:%d I%c A%d:%d C%s\n",
+ ptr->sp.video.w,
+ ptr->sp.video.h,
+ ptr->sp.video.fps_n,
+ ptr->sp.video.fps_d,
+ ptr->sp.video.i?(ptr->sp.video.i==TOP_FIRST?'t':'b'):'p',
+ ptr->sp.video.pa_n,
+ ptr->sp.video.pa_d,
+ chromaformat[ptr->sp.video.format]);
+ break;
+ default:
+ yerror("Unknown stream type in output filter.\n");
+ exit(1);
+ }
}
+ }
- switch(ptr->st){
- case STREAM_AUDIO:
- fprintf(i->outfile,"AUDIO R%d C%d\n",
- ptr->sp.audio.rate,ptr->sp.audio.ch);
- break;
- case STREAM_VIDEO:
- fprintf(i->outfile,"VIDEO W%d H%d F%d:%d I%c A%d:%d C%s\n",
- ptr->sp.video.w,
- ptr->sp.video.h,
- ptr->sp.video.fps_n,
- ptr->sp.video.fps_d,
- ptr->sp.video.i?(ptr->sp.video.i==TOP_FIRST?'t':'b'):'p',
- ptr->sp.video.pa_n,
- ptr->sp.video.pa_d,
- chromaformat[ptr->sp.video.format]);
- break;
- default:
- yerror("Unknown stream type in output filter.\n");
- exit(1);
+ if(i->wavfile){
+
+ for(j=0;j<queue->streams;j++){
+ fq_frame_t *ptr = queue->tail;
+ while(ptr && ptr->sno != j)
+ ptr=ptr->next;
+
+ if(!ptr){
+ yerror("Output couldn't find stream number %d\n\n",j);
+ exit(1);
+ }
+
+ if(ptr->st==STREAM_AUDIO){
+ yinfo("stream %d -> %s\n",ptr->sno,i->wavfilename);
+ i->wavno = ptr->sno;
+ i->wavrate = ptr->sp.audio.rate;
+ i->wavch = ptr->sp.audio.ch;
+ waveheader(i,0x7fffffff); /* bogus size initially */
+ /* amend with correct duration later if possible */
+ break;
+ }
}
+ if(i->wavno<0){
+ ywarn("No audio streams found; closing WAV file\n");
+ fclose(i->wavfile);
+ i->wavfile=NULL;
+ }
}
+
+ if(i->yuvfile){
+
+ for(j=0;j<queue->streams;j++){
+ fq_frame_t *ptr = queue->tail;
+ while(ptr && ptr->sno != j)
+ ptr=ptr->next;
+
+ if(!ptr){
+ yerror("Output couldn't find stream number %d\n\n",j);
+ exit(1);
+ }
+
+ if(ptr->st==STREAM_VIDEO){
+ yinfo("stream %d -> %s\n",ptr->sno,i->yuvfilename);
+ i->yuvno = ptr->sno;
+
+ if(!translateformat1[ptr->sp.video.format]){
+ if(!translateformat2[ptr->sp.video.format]){
+ yerror("No YUV4MPEG output fallback implemented for pixel format C%s.\n\n",
+ chromaformat[ptr->sp.video.format]);
+ exit(1);
+ }else{
+ ywarn("YUV4MPEG2 has no equivalent to pixel format C%s\n",
+ chromaformat[ptr->sp.video.format]);
+ ywarn("using C%s as fallback; colors may be shifted 1/2 pixel\n\n",
+ translateformat2[ptr->sp.video.format]);
+ }
+ }
+
+ fprintf(i->yuvfile,"YUV4MPEG2 W%d H%d F%d:%d I%c A%d:%d C%s\n",
+ ptr->sp.video.w,
+ ptr->sp.video.h,
+ ptr->sp.video.fps_n,
+ ptr->sp.video.fps_d,
+ ptr->sp.video.i?(ptr->sp.video.i==TOP_FIRST?'t':'b'):'p',
+ ptr->sp.video.pa_n,
+ ptr->sp.video.pa_d,
+ translateformat2[ptr->sp.video.format]);
+ }
+ }
+
+ if(i->yuvno<0){
+ ywarn("No video streams found; closing YUV4MPEG2 file\n");
+ fclose(i->yuvfile);
+ i->yuvfile=NULL;
+ }
+ }
+
i->wrote_header=1;
}else
return;
@@ -128,8 +297,10 @@
queue. The queue is uninitialized; only filter options are
filled in. */
- queue->internal = calloc(1,sizeof(*i));
+ i = queue->internal = calloc(1,sizeof(*i));
parse_options(queue);
+ i->wavno=-1;
+ i->yuvno=-1;
break;
case QUEUE_STARTUP:
@@ -155,11 +326,31 @@
while((ptr=queue->tail)){
if(ptr->body){
- if(fprintf(i->outfile,"FRAME S%d L%d P%.3f\n",ptr->sno,ptr->body_size,ptr->pts)<0 ||
- fwrite(ptr->body,1,ptr->body_size,i->outfile)<(unsigned)ptr->body_size){
- yerror("Unable to write to output; %s\n",strerror(errno));
- exit(1);
+
+ if(i->outfile){
+ if(fprintf(i->outfile,"FRAME S%d L%d P%.3f\n",ptr->sno,ptr->body_size,ptr->pts)<0 ||
+ fwrite(ptr->body,1,ptr->body_size,i->outfile)<(unsigned)ptr->body_size){
+ yerror("Unable to write to output; %s\n",strerror(errno));
+ exit(1);
+ }
}
+
+ if(i->wavfile && ptr->sno==i->wavno){
+ /* 24 -> 16 */
+ int j;
+ for(j=0;j<ptr->body_size;j+=3){
+ fputc(ptr->body[j+1],i->wavfile);
+ fputc(ptr->body[j+2],i->wavfile);
+ }
+ }
+
+ if(i->yuvfile && ptr->sno==i->yuvno){
+ if(fprintf(i->yuvfile,"FRAME\n")<0 ||
+ fwrite(ptr->body,1,ptr->body_size,i->yuvfile)<(unsigned)ptr->body_size){
+ yerror("Unable to write to YUV output; %s\n",strerror(errno));
+ exit(1);
+ }
+ }
}
/* It's possible something follows this output filter. Safe to call
@@ -169,8 +360,25 @@
}
if(queue->state==QUEUE_FLUSH){
- fclose(i->outfile);
- i->outfile=NULL;
+ if(i->outfile){
+ fclose(i->outfile);
+ i->outfile=NULL;
+ }
+
+ if(i->wavfile){
+ /* update duration is possible */
+ if(!fseek(i->wavfile,0,SEEK_SET))
+ waveheader(i,i->wavebytes);
+
+ fclose(i->wavfile);
+ i->wavfile=NULL;
+ }
+
+ if(i->yuvfile){
+ fclose(i->yuvfile);
+ i->yuvfile=NULL;
+ }
+
queue->state=QUEUE_FINISHED;
}
break;
More information about the commits
mailing list