lav2wav.c
来自「Motion JPEG编解码器源代码」· C语言 代码 · 共 413 行
C
413 行
/* * * lav2wav.c * * Copyright (C) 2000 MSSG, Rainer Johanni, Aaron Holtzman, Andrew Stevens * * This file is part of lav2wav,a component of the "MJPEG tools" * suite of open source tools for MJPEG and MPEG processing. * * lav2wav 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. * * lav2wav 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 <config.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "lav_io.h"#include "editlist.h"#include "mjpeg_logging.h"#include "lav2wav.h"struct wave_header wave;int verbose = 1;int big_endian; /* The endian detection */static uint8_t audio_buff[2*256*1024]; /* Enough for 1fps, 48kHz ... */int silence_sr, silence_bs, silence_ch ; EditList el;void set_silence (char *);int wav_header( unsigned int bits, unsigned int rate, unsigned int channels, int fd );void Usage(char *str);/* Raw write does *not* guarantee to write the entire buffer load if it becomes possible to do so. This does... */static size_t do_write( int fd, void *buf, size_t count ){ char *cbuf = buf; size_t count_left = count; size_t written; while( count_left > 0 ) { written = write( fd, cbuf, count_left ); if( written < 0 ) { return count-count_left; } count_left -= written; cbuf += written; } return count;}int wav_header( unsigned int bits, unsigned int rate, unsigned int channels, int fd ){ uint16_t temp_16; /* temp variables for swapping the bytes */ uint32_t temp_32; /* temp variables for swapping the bytes */ uint32_t dummy_size = 0x7fffff00+sizeof(wave); /* Write out a ZEROD wave header first */ memset(&wave, 0, sizeof(wave)); strncpy((char*)wave.riff.id, "RIFF", 4); strncpy((char*)wave.riff.wave_id, "WAVE",4); dummy_size -=8; wave.riff.len = reorder_32(dummy_size, big_endian); strncpy((char*)wave.format.id, "fmt ",4); wave.format.len = reorder_32((uint32_t)sizeof(struct common_struct), big_endian); /* Store information */ if (big_endian == 0) { wave.common.wFormatTag = WAVE_FORMAT_PCM; wave.common.wChannels = channels; wave.common.dwSamplesPerSec = rate; wave.common.dwAvgBytesPerSec = channels*rate*bits/8; wave.common.wBlockAlign = channels*bits/8; wave.common.wBitsPerSample = bits; } else /* We have a big endian machine and have to swapp the bytes */ { temp_16 = WAVE_FORMAT_PCM; swab(&temp_16, &wave.common.wFormatTag,2); temp_16 = channels; swab(&temp_16, &wave.common.wChannels, 2); temp_32 = rate; wave.common.dwSamplesPerSec = reorder_32 (temp_32, big_endian); temp_32 = channels*rate*bits/8; wave.common.dwAvgBytesPerSec = reorder_32 (temp_32, big_endian); temp_16 = channels*bits/8; swab(&temp_16, &wave.common.wBlockAlign, 2); temp_16 = bits; swab(&temp_16, &wave.common.wBitsPerSample, 2); } strncpy((char*)wave.data.id, "data",4); dummy_size -= 20+sizeof(struct common_struct); wave.data.len = reorder_32 (dummy_size, big_endian); if (do_write(fd, &wave, sizeof(wave)) != sizeof(wave)) return 1; return 0;}static void wav_close(int fd){ unsigned int size; /* Find how long our file is in total, including header */ size = lseek(fd, 0, SEEK_CUR); if (size < 0 ) { if( fd > 2 ) { mjpeg_error("lseek failed - wav-header is corrupt"); } goto EXIT; } /* Rewind file */ if (lseek(fd, 0, SEEK_SET) < 0) { mjpeg_error("rewind failed - wav-header is corrupt"); goto EXIT; } mjpeg_debug("Writing WAV header"); /* Fill out our wav-header with some information. */ size -= 8; wave.riff.len = reorder_32 ((uint32_t)size, big_endian); size -= 20+sizeof(struct common_struct); wave.data.len = reorder_32 ((uint32_t)size, big_endian); if (do_write(fd, &wave, sizeof(wave)) < sizeof(wave)) { mjpeg_error("wav-header write failed -- file is corrupt"); goto EXIT; } mjpeg_info("WAV done");EXIT: close(fd);}/* The typical help output */void Usage(char *str){ fprintf(stderr, "Usage: %s [options] inputfiles\n",str); fprintf(stderr, "where options are:\n"); fprintf(stderr, "-o num Start extracting at video frame (num)\n"); fprintf(stderr, "-f num Extract (num) frames of audio\n"); fprintf(stderr, "-s/-c Backwards compatibility options for -o/-f\n"); fprintf(stderr, "-v num verbose level [0..2]\n"); fprintf(stderr, "-I Ignore unsupported bitrates/bits per sample\n"); fprintf(stderr, "-r sr,bs,ch If the file does not contain any sound generate silence\n"); fprintf(stderr, " sr samplerate 32000,44100,48000 bs bytesize 8,16, ch channes 1/2\n"); fprintf(stderr, "-R The same as -r but now a silence with 44100, 16, 2 is created\n"); exit(0);}/* Setting the type of silence, samplerate, bitesize, chanels */void set_silence (char *optarg){unsigned int u1, u2, u3; int i;i = (sscanf (optarg, "%i,%i,%i", &u1, &u2, &u3));if (i != 3) { mjpeg_error("Wrong number of arguments given to the -r option"); exit(1); }else /*Setting user chosen values */ { if ( (u1 == 32000) || (u1 == 44100) || (u1 == 48000) ) silence_sr = u1; else { mjpeg_error("Wrong sampelrate use: 32000,44100,48000, exiting"); exit(1); } if ( (u2 == 8) || (u2 == 16) ) silence_bs = u2; else { mjpeg_error("Wrong audio bitsize use 8 or 16, exiting"); exit(1); } if ( (u3 == 1) || (u3 == 2) ) silence_ch = u3; else { mjpeg_error("Wrong number of chanels use 1 or 2, exiting"); exit(1); } }mjpeg_info("Setting silence to %i sampelrate, %i bitsize, %i chanels", silence_sr, silence_bs, silence_ch);}intmain(argc, argv)int argc;char **argv;{ int n,f,i; int res; int warned = 0; int start_frame = 0; int num_frames = -1; int ignore_bitrate = 0; int fragments; unsigned int fred; char *pfred; silence_sr=0; /* silence_sr is use for detecting if the -r option is used */silence_bs=0; silence_ch=0; while( (n=getopt(argc,argv,"v:s:r:Rc:o:f:I")) != EOF) { switch(n) { case 'v': verbose = atoi(optarg); if( verbose < 0 || verbose > 2 ) Usage(argv[0]); break; case 'o': case 's': start_frame = atoi(optarg); break; case 'r': set_silence(optarg); break; case 'R': silence_sr=44100; silence_bs=16; silence_ch=2; break; case 'f': case 'c': num_frames = atoi(optarg); break; case 'I': ignore_bitrate = 1; break; case '?': Usage(argv[0]); } } /* The endiat detection copied from mp2enc */ fred = 2 | (1 << (sizeof(int)*8-8)); pfred = (char *)&fred; if(*pfred == 1) { big_endian = 1; mjpeg_info("System is big endian"); } else if(*pfred == 2) { big_endian = 0; mjpeg_info("System is little endian"); } else { mjpeg_error("Can not determine if system is big/lttle endian"); mjpeg_error_exit1("Are you running on a Cray - or what?"); } /* Open editlist */ if( argc-optind < 1) Usage(argv[0]); (void)mjpeg_default_handler_verbosity(verbose); read_video_files(argv + optind, argc - optind, &el,0); if(!el.has_audio) { if (silence_sr == 0) { mjpeg_error("Input file(s) have no audio, use the -r option to generate silence"); exit(1); } else { mjpeg_info("mjpeg_framerate %f ", el.video_fps); /* Create wav header (skeleton) on stdout ... */ /* audio_bits, audio_rate, audio_chans */ wav_header( silence_bs, silence_sr, silence_ch, 1); /* skip to the start frame if specified */ f = 0; if (start_frame != 0) f = start_frame; /* num_frames = -1, read em all, else read specified # */ if ( num_frames == -1) num_frames = el.video_frames; fragments = silence_sr / el.video_fps; /* Here is a dirty hack for the number of fragments we put out I dont know a other way how to put out a certain number of \x00 So we put always 4bytes of 00h out and reduce the number of fragments. Works perfect for PAL framerate. But in NTSC there is a round problem. At 44k1Hz, 16bs 2ch 0,47 samples/frame That means that we have on second offset per hour of film */ if (silence_bs == 8) fragments = fragments / 2; if (silence_ch == 1) fragments = fragments / 2; /* Stream out audio wav-style... in per-frame chunks */ for( ; f < num_frames; ++f ) { for ( i = 0; i < fragments ; i++) do_write (1, "\x0000000", 4); } wav_close(1); exit(0); } } if (!ignore_bitrate) { if(el.audio_bits!=16) { mjpeg_error("Input file(s) must have 16 bit audio!"); exit(1); } switch (el.audio_rate) { case 48000 : case 44100 : case 32000 : break; default: mjpeg_error("Audio rate is %ld Hz",el.audio_rate); mjpeg_error("Audio rate must be 32000, 44100 or 48000 !"); exit(1); } } switch (el.audio_chans) { case 1: case 2: break; default: mjpeg_error("Audio channels %d not allowed",el.audio_chans); exit(1); } /* Create wav header (skeleton) on stdout ... */ wav_header( el.audio_bits, el.audio_rate, el.audio_chans, 1); /* skip to the start frame if specified */ f = 0; if (start_frame != 0) f = start_frame; /* num_frames = -1, read em all, else read specified # */ if ( num_frames == -1) num_frames = el.video_frames; /* Stream out audio wav-style... in per-frame chunks */ for( ; f < num_frames; ++f ) { n = el_get_audio_data(audio_buff, f, &el, 0); if( n < 0 ) { mjpeg_error_exit1( "%s: Couldn't get audio for frame %d!", argv[0], f ); } if( n != 0 ) { res = do_write( 1, audio_buff, n ); if( res != n ) { mjpeg_error_exit1( "%s: Couldn't write audio for frame %d!", argv[0], f ); exit(1); } } else if( f < num_frames && ! warned ) { mjpeg_warn( "%s: audio ends early at frame %d", argv[0], f ); warned = 1; } } wav_close(1); exit(0);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?