[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