📄 transcoder_example.c
字号:
/******************************************************************** * * * THIS FILE IS PART OF THE OggTheora SOFTWARE CODEC SOURCE CODE. * * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * * * * THE Theora SOURCE CODE IS COPYRIGHT (C) 2002-2004 * * by the Xiph.Org Foundation http://www.xiph.org/ * * * ******************************************************************** function: example encoder application; makes an Ogg Theora/Vorbis file from YUV4MPEG2 and WAV input last mod: $Id: transcoder_example.c,v 1.4 2004/03/20 00:14:04 tterribe Exp $ ********************************************************************/#define _GNU_SOURCE#define _REENTRANT#define _LARGEFILE_SOURCE#define _LARGEFILE64_SOURCE#define _FILE_OFFSET_BITS 64#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <getopt.h>#include <time.h>#include <math.h>#include "theora/theora.h"#include "vorbis/codec.h"#include "vorbis/vorbisenc.h"#ifdef _WIN32/*supply missing headers and functions to Win32. going to hell, I know*/#include <io.h>#include <fcntl.h>static double rint(double x){ if (x < 0.0) return (double)(int)(x - 0.5); else return (double)(int)(x + 0.5);}#endif/*Copied from vorbis/sharedbook.c*/static int _ilog(unsigned int v){ int ret=0; while(v){ ret++; v>>=1; } return(ret);}const char *optstring = "o:a:A:v:V:";struct option options [] = { {"output",required_argument,NULL,'o'}, {"audio-rate-target",required_argument,NULL,'A'}, {"video-rate-target",required_argument,NULL,'V'}, {"audio-quality",required_argument,NULL,'a'}, {"video-quality",required_argument,NULL,'v'}, {NULL,0,NULL,0}};typedef struct TC_INSTANCE { ogg_uint32_t LastKeyFrame ; ogg_int64_t KeyFrameCount; int ThisIsFirstFrame; int ThisIsKeyFrame; ogg_uint32_t CurrentFrame; ogg_int64_t granulepos; int keyframe_granule_shift; char * in_bytes; long in_bytecount; ogg_uint32_t fps_denominator; ogg_uint32_t fps_numerator; oggpack_buffer opb_in; oggpack_buffer opb_out;} TC_INSTANCE;/* You'll go to Hell for using globals. */FILE *audio=NULL;FILE *video=NULL;int audio_ch=0;int audio_hz=0;float audio_q=.1;int audio_r=-1;int video_x=0;int video_y=0;int frame_x=0;int frame_y=0;int frame_x_offset=0;int frame_y_offset=0;int video_hzn=0;int video_hzd=0;int video_an=0;int video_ad=0;int video_r=-1;int video_q=16; char *vp3frame[2]; int framebytecount[2]; int frameiskey[2]; ogg_page audiopage; ogg_page videopage;static void usage(void){ fprintf(stderr, "Usage: encoder_example [options] [audio_file] video_file\n\n" "Options: \n\n" " -o --output <filename.ogg> file name for encoded output;\n" " If this option is not given, the\n" " compressed data is sent to stdout.\n\n" " -A --audio-rate-target <n> bitrate target for Vorbis audio;\n" " use -a and not -A if at all possible,\n" " as -a gives higher quality for a given\n" " bitrate.\n\n" " -V --video-rate-target <n> bitrate target for Theora video\n\n" " -a --audio-quality <n> Vorbis quality selector from -1 to 10\n" " (-1 yields smallest files but lowest\n" " fidelity; 10 yields highest fidelity\n" " but large files. '2' is a reasonable\n" " default).\n\n" " -v --video-quality <n> Theora quality selector fro 0 to 10\n" " (0 yields smallest files but lowest\n" " video quality. 10 yields highest\n" " fidelity but large files).\n\n" "encoder_example accepts only uncompressed RIFF WAV format audio and\n" "YUV4MPEG2 uncompressed video.\n\n"); exit(1);}static void id_file(char *f){ FILE *test; unsigned char buffer[80]; int ret; /* open it, look for magic */ if(!strcmp(f,"-")){ /* stdin */ test=stdin; }else{ test=fopen(f,"rb"); if(!test){ fprintf(stderr,"Unable to open file %s.\n",f); exit(1); } } ret=fread(buffer,1,4,test); if(ret<4){ fprintf(stderr,"EOF determining file type of file %s.\n",f); exit(1); } if(!memcmp(buffer,"RIFF",4)){ /* possible WAV file */ if(audio){ /* umm, we already have one */ fprintf(stderr,"Multiple RIFF WAVE files specified on command line.\n"); exit(1); } /* Parse the rest of the header */ ret=fread(buffer,1,4,test); ret=fread(buffer,1,4,test); if(ret<4)goto riff_err; if(!memcmp(buffer,"WAVE",4)){ while(!feof(test)){ ret=fread(buffer,1,4,test); if(ret<4)goto riff_err; if(!memcmp("fmt",buffer,3)){ /* OK, this is our audio specs chunk. Slurp it up. */ ret=fread(buffer,1,20,test); if(ret<20)goto riff_err; if(memcmp(buffer+4,"\001\000",2)){ fprintf(stderr,"The WAV file %s is in a compressed format; " "can't read it.\n",f); exit(1); } audio=test; audio_ch=buffer[6]+(buffer[7]<<8); audio_hz=buffer[8]+(buffer[9]<<8)+ (buffer[10]<<16)+(buffer[11]<<24); if(buffer[18]+(buffer[19]<<8)!=16){ fprintf(stderr,"Can only read 16 bit WAV files for now.\n"); exit(1); } /* Now, align things to the beginning of the data */ /* Look for 'dataxxxx' */ while(!feof(test)){ ret=fread(buffer,1,4,test); if(ret<4)goto riff_err; if(!memcmp("data",buffer,4)){ /* We're there. Ignore the declared size for now. */ ret=fread(buffer,1,4,test); if(ret<4)goto riff_err; fprintf(stderr,"File %s is 16 bit %d channel %d Hz RIFF WAV audio.\n", f,audio_ch,audio_hz); return; } } } } } fprintf(stderr,"Couldn't find WAVE data in RIFF file %s.\n",f); exit(1); } if(!memcmp(buffer,"AVI2",4)){ /* possible AVI2VP31 format file */ /* read until newline, or 80 cols, whichever happens first */ int i; for(i=0;i<79;i++){ ret=fread(buffer+i,1,1,test); if(ret<1)goto yuv_err; if(buffer[i]=='\n')break; } if(i==79){ fprintf(stderr,"Error parsing %s header; not a VP31 raw frames file?\n",f); } buffer[i]='\0'; if(!memcmp(buffer,"VP31",4)){ char interlace; if(video){ /* umm, we already have one */ fprintf(stderr,"Multiple video files specified on command line.\n"); exit(1); } if(buffer[4]!='R'){ fprintf(stderr,"Incorrect file ; VP31 raw frames required.\n"); } ret=sscanf(buffer,"VP31R W%d H%d F%d:%d I%c A%d:%d", &frame_x,&frame_y,&video_hzn,&video_hzd,&interlace, &video_an,&video_ad); if(ret<7){ fprintf(stderr,"Error parsing AVI2VP31R header in file %s.\n",f); exit(1); } if(interlace!='p'){ fprintf(stderr,"Input video is interlaced; Theora handles only progressive scan\n"); exit(1); } video=test; fprintf(stderr,"File %s is %dx%d %.02f fps VP31 video.\n", f,frame_x,frame_y,(double)video_hzn/video_hzd); return; } } fprintf(stderr,"Input file %s is neither a WAV nor VP31 file.\n",f); exit(1); riff_err: fprintf(stderr,"EOF parsing RIFF file %s.\n",f); exit(1); yuv_err: fprintf(stderr,"EOF parsing VP31 file %s.\n",f); exit(1);}int spinner=0;char *spinascii="|/-\\";void spinnit(void){ spinner++; if(spinner==4)spinner=0; fprintf(stderr,"\r%c",spinascii[spinner]);}int fetch_and_process_audio(FILE *audio,ogg_page *audiopage, ogg_stream_state *vo, vorbis_dsp_state *vd, vorbis_block *vb, int audioflag){ ogg_packet op; int i,j; while(audio && !audioflag){ /* process any audio already buffered */ spinnit(); if(ogg_stream_pageout(vo,audiopage)>0) return 1; if(ogg_stream_eos(vo))return 0; { /* read and process more audio */ signed char readbuffer[4096]; int toread=4096/2/audio_ch; int bytesread=fread(readbuffer,1,toread*2*audio_ch,audio); int sampread=bytesread/2/audio_ch; float **vorbis_buffer; int count=0; if(bytesread<=0){ /* end of file. this can be done implicitly, but it's easier to see here in non-clever fashion. Tell the library we're at end of stream so that it can handle the last frame and mark end of stream in the output properly */ vorbis_analysis_wrote(vd,0); }else{ vorbis_buffer=vorbis_analysis_buffer(vd,sampread); /* uninterleave samples */ for(i=0;i<sampread;i++){ for(j=0;j<audio_ch;j++){ vorbis_buffer[j][i]=((readbuffer[count+1]<<8)| (0x00ff&(int)readbuffer[count]))/32768.f; count+=2; } } vorbis_analysis_wrote(vd,sampread); } while(vorbis_analysis_blockout(vd,vb)==1){ /* analysis, assume we want to use bitrate management */ vorbis_analysis(vb,NULL); vorbis_bitrate_addblock(vb); /* weld packets into the bitstream */ while(vorbis_bitrate_flushpacket(vd,&op)) ogg_stream_packetin(vo,&op); } } } return audioflag;}int theora_transcode_packetout( TC_INSTANCE *ttc, int last_p, ogg_packet *op){ long bytes=ttc->in_bytecount; if(!bytes)return(0); op->packet=ttc->in_bytes; op->bytes=bytes; op->b_o_s=0; op->e_o_s=last_p; op->packetno=ttc->CurrentFrame; op->granulepos=ttc->granulepos; return 1;}void TranscodeKeyFrame(TC_INSTANCE *ttc){ /* Keep track of the total number of Key Frames Coded */ ttc->KeyFrameCount += 1; ttc->LastKeyFrame = 1;}void TranscodeFrame(TC_INSTANCE *ttc){ ttc->LastKeyFrame++;}void TranscodeFirstFrame(TC_INSTANCE *ttc){ /* Keep track of the total number of Key Frames Coded. */ ttc->KeyFrameCount = 1; ttc->LastKeyFrame = 1;}int theora_transcode_bufferin( TC_INSTANCE *ttc, int isKeyFrame, char * bytes, int bytecount){ /*transcode: record keyframe flag*/ ttc->ThisIsKeyFrame = isKeyFrame; /* Special case for first frame */ if ( ttc->ThisIsFirstFrame ){ ttc->ThisIsFirstFrame = 0; ttc->ThisIsKeyFrame = 0; } else if ( ttc->ThisIsKeyFrame ) { TranscodeKeyFrame(ttc); ttc->ThisIsKeyFrame = 0; } else { /* Compress the frame. */ TranscodeFrame( ttc ); } /*need to pack info here*/ { int frame_type; long total_bits; long total_words; int frac_bits; oggpackB_readinit(&ttc->opb_in,bytes,bytecount); oggpackB_reset(&ttc->opb_out); /*Mark as video frame.*/ oggpackB_write(&ttc->opb_out,0,1); /*Copy frame type.*/ frame_type=oggpackB_read1(&ttc->opb_in); oggpackB_write(&ttc->opb_out,frame_type,1); /*Skip an unused bit in the VP32 header.*/ oggpackB_adv1(&ttc->opb_in); /*Copy Q multiplier.*/ oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,6),6); /*VP3 has no per-block Q multipliers*/ oggpackB_write(&ttc->opb_out,0,1); /*If the frame is a base/key/golden frame, copy a few extra bits.*/ if(frame_type==0){ /*These 13 bits are not included in a Theora frame header. They were 0's and VP3 version info in VP32.*/ oggpackB_adv(&ttc->opb_in,13); /*Copy the key frame type and the spare configuration bits.*/ oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,3),3); } /*Copy the rest of the bits over.*/ total_bits=bytecount*8-oggpack_bits(&ttc->opb_in); frac_bits=(int)(total_bits&31); if(frac_bits){ oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,frac_bits), frac_bits); } total_words=total_bits>>5; while(total_words-->0){ oggpackB_write(&ttc->opb_out,oggpackB_read(&ttc->opb_in,32),32); } ttc->in_bytecount = oggpackB_bytes(&ttc->opb_out); ttc->in_bytes = oggpackB_get_buffer(&ttc->opb_out); } /* Update stats variables. */ ttc->CurrentFrame++; ttc->granulepos= ((ttc->CurrentFrame-ttc->LastKeyFrame-1)<<ttc->keyframe_granule_shift)+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -