📄 editlist.c
字号:
/* This program 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 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.*/#include <config.h>#include <stdio.h>#include <string.h>#include <limits.h>#include <stdlib.h>#include <errno.h>#include "mjpeg_logging.h"#include "lav_io.h"#include "editlist.h"#include <math.h>/* Since we use malloc often, here the error handling */static void malloc_error(void){ mjpeg_error_exit1("Out of memory - malloc failed");}int open_video_file(char *filename, EditList *el, int preserve_pathname){ int i, n, nerr; char realname[PATH_MAX]; /* Get full pathname of file if the user hasn't specified preservation of pathnames... */ if( preserve_pathname ) { strcpy(realname, filename); } else if(realpath(filename,realname)==0) { mjpeg_error_exit1( "Cannot deduce real filename: %s", strerror(errno)); } /* Check if this filename is allready present */ for(i=0;i<el->num_video_files;i++) if(strcmp(realname,el->video_file_list[i])==0) { mjpeg_error("File %s already open",realname); return i; } /* Check if MAX_EDIT_LIST_FILES will be exceeded */ if(el->num_video_files>=MAX_EDIT_LIST_FILES) { mjpeg_error_exit1("Maximum number of video files exceeded"); } n = el->num_video_files; el->num_video_files++; mjpeg_debug("Opening video file %s ...",filename); el->lav_fd[n] = lav_open_input_file(filename); if(!el->lav_fd[n]) { mjpeg_error_exit1("Error opening %s",filename); } if(lav_video_MJPG_chroma(el->lav_fd[n]) != CHROMA422 && lav_video_MJPG_chroma(el->lav_fd[n]) != CHROMA420) { mjpeg_warn("Input file %s is not in JPEG 4:2:2 or 4:2:0 format", filename); el->MJPG_chroma = CHROMAUNKNOWN; } el->num_frames[n] = lav_video_frames(el->lav_fd[n]); el->video_file_list[n] = strdup(realname); if(el->video_file_list[n]==0) malloc_error(); /* Debug Output */ mjpeg_debug("File: %s, absolute name: %s",filename,realname); mjpeg_debug(" frames: %8ld",lav_video_frames(el->lav_fd[n])); mjpeg_debug(" width: %8d",lav_video_width (el->lav_fd[n])); mjpeg_debug(" height: %8d",lav_video_height(el->lav_fd[n])); { const char *int_msg; switch( lav_video_interlacing(el->lav_fd[n])) { case LAV_NOT_INTERLACED : int_msg = "not interlaced"; break; case LAV_INTER_TOP_FIRST : int_msg = "top field first"; break; case LAV_INTER_BOTTOM_FIRST : int_msg = "bottom field first"; break; default: int_msg = "Unknown!"; break; } mjpeg_debug(" interlacing: %s", int_msg ); } mjpeg_debug(" frames/sec: %8.3f",lav_frame_rate(el->lav_fd[n])); mjpeg_debug(" audio samps: %8ld",lav_audio_samples(el->lav_fd[n])); mjpeg_debug(" audio chans: %8d",lav_audio_channels(el->lav_fd[n])); mjpeg_debug(" audio bits: %8d",lav_audio_bits(el->lav_fd[n])); mjpeg_debug(" audio rate: %8ld",lav_audio_rate(el->lav_fd[n])); nerr = 0; if(n==0) { /* First file determines parameters */ el->video_height = lav_video_height(el->lav_fd[n]); el->video_width = lav_video_width (el->lav_fd[n]); el->video_inter = lav_video_interlacing(el->lav_fd[n]); el->video_fps = lav_frame_rate(el->lav_fd[n]); lav_video_sampleaspect(el->lav_fd[n], &el->video_sar_width, &el->video_sar_height); if(!el->video_norm) { /* TODO: This guessing here is a bit dubious but it can be over-ridden */ if(el->video_fps>24.95 && el->video_fps<25.05) el->video_norm = 'p'; else if (el->video_fps>29.92 && el->video_fps<=30.02) el->video_norm = 'n'; else { mjpeg_error_exit1("File %s has %f frames/sec, choose norm with +[np] param", filename,el->video_fps); } } el->audio_chans = lav_audio_channels(el->lav_fd[n]); if(el->audio_chans>2) { mjpeg_error_exit1("File %s has %d audio channels - cant play that!", filename,el->audio_chans); } el->has_audio = (el->audio_chans>0); el->audio_bits = lav_audio_bits(el->lav_fd[n]); el->audio_rate = lav_audio_rate(el->lav_fd[n]); el->audio_bps = (el->audio_bits*el->audio_chans+7)/8; } else { /* All files after first have to match the paramters of the first */ if( el->video_height != lav_video_height(el->lav_fd[n]) || el->video_width != lav_video_width (el->lav_fd[n]) ) { mjpeg_error("File %s: Geometry %dx%d does not match %ldx%ld", filename,lav_video_width (el->lav_fd[n]), lav_video_height(el->lav_fd[n]),el->video_width,el->video_height); nerr++; } if( el->video_inter != lav_video_interlacing(el->lav_fd[n]) ) { mjpeg_error("File %s: Interlacing is %d should be %ld", filename,lav_video_interlacing(el->lav_fd[n]),el->video_inter); nerr++; } if( fabs(el->video_fps - lav_frame_rate(el->lav_fd[n])) > 0.0000001) { mjpeg_error("File %s: fps is %3.2f should be %3.2f", filename, lav_frame_rate(el->lav_fd[n]), el->video_fps); nerr++; } /* If first file has no audio, we don't care about audio */ if(el->has_audio) { if(el->audio_chans != lav_audio_channels(el->lav_fd[n]) || el->audio_bits != lav_audio_bits(el->lav_fd[n]) || el->audio_rate != lav_audio_rate(el->lav_fd[n]) ) { mjpeg_error("File %s: Audio is %d chans %d bit %ld Hz," " should be %d chans %d bit %ld Hz", filename,lav_audio_channels(el->lav_fd[n]), lav_audio_bits(el->lav_fd[n]), lav_audio_rate(el->lav_fd[n]), el->audio_chans, el->audio_bits, el->audio_rate); nerr++; } } if(nerr) exit(1); } return n;}/* read_video_files: Accepts a list of filenames as input and opens these files for subsequent playback. The list of filenames may consist of: - "+p" or "+n" as the first entry (forcing PAL or NTSC) - ordinary AVI or Quicktimefile names - Edit list file names - lines starting with a colon (:) are ignored for third-party editlist extensions*/void read_video_files(char **filename, int num_files, EditList *el, int preserve_pathnames){ FILE *fd; char line[1024]; long index_list[MAX_EDIT_LIST_FILES]; int i, n, nf, n1, n2, nl, num_list_files; nf = 0; memset(el,0,sizeof(EditList)); el->MJPG_chroma = CHROMA422; /* will be reset if not the case for all files */ /* Check if a norm parameter is present */ if(strcmp(filename[0],"+p")==0 || strcmp(filename[0],"+n")==0) { el->video_norm = filename[0][1]; nf = 1; mjpeg_info("Norm set to %s",el->video_norm=='n'?"NTSC":"PAL"); } for(;nf<num_files;nf++) { /* Check if filename[nf] is a edit list */ fd = fopen(filename[nf],"r"); if(fd==0) { mjpeg_error_exit1("Error opening %s: %s",filename[nf], strerror(errno)); } fgets(line,1024,fd); if(strcmp(line,"LAV Edit List\n")==0) { /* Ok, it is a edit list */ mjpeg_debug( "Edit list %s opened",filename[nf]); /* Read second line: Video norm */ fgets(line,1024,fd); if(line[0]!='N' && line[0]!='n' && line[0]!='P' && line[0]!='p') { mjpeg_error_exit1("Edit list second line is not NTSC/PAL"); } mjpeg_debug("Edit list norm is %s",line[0]=='N'||line[0]=='n'?"NTSC":"PAL"); if(line[0]=='N'||line[0]=='n') { if( el->video_norm == 'p') { mjpeg_error_exit1("Norm allready set to PAL"); } el->video_norm = 'n'; } else { if( el->video_norm == 'n') { mjpeg_error_exit1("Norm allready set to NTSC"); } el->video_norm = 'p'; } /* read third line: Number of files */ fgets(line,1024,fd); sscanf(line,"%d",&num_list_files); mjpeg_debug("Edit list contains %d files",num_list_files); /* read files */ for(i=0;i<num_list_files;i++) { fgets(line,1024,fd); n = strlen(line); if(line[n-1]!='\n') { mjpeg_error_exit1("Filename in edit list too long"); } line[n-1] = 0; /* Get rid of \n at end */ index_list[i] = open_video_file(line,el,preserve_pathnames); } /* Read edit list entries */ while(fgets(line,1024,fd)) { if(line[0]!=':') /* ignore lines starting with a : */ { sscanf(line,"%d %d %d",&nl,&n1,&n2); if(nl<0 || nl>=num_list_files) { mjpeg_error_exit1("Wrong file number in edit list entry"); } if(n1<0) n1 = 0; if(n2>=el->num_frames[index_list[nl]]) n2 = el->num_frames[index_list[nl]]; if(n2<n1) continue; el->frame_list = (long*) realloc(el->frame_list, (el->video_frames+n2-n1+1)*sizeof(long)); if(el->frame_list==0) malloc_error(); for(i=n1;i<=n2;i++) el->frame_list[el->video_frames++] = EL_ENTRY(index_list[nl],i); } } fclose(fd); } else { /* Not an edit list - should be a ordinary video file */ fclose(fd); n = open_video_file(filename[nf],el, preserve_pathnames); el->frame_list = (long*) realloc(el->frame_list, (el->video_frames+el->num_frames[n])*sizeof(long)); if(el->frame_list==0) malloc_error(); for(i=0;i<el->num_frames[n];i++) el->frame_list[el->video_frames++] = EL_ENTRY(n,i); } } /* Calculate maximum frame size */ for(i=0;i<el->video_frames;i++) { n = el->frame_list[i]; if(lav_frame_size(el->lav_fd[N_EL_FILE(n)],N_EL_FRAME(n)) > el->max_frame_size) el->max_frame_size = lav_frame_size(el->lav_fd[N_EL_FILE(n)],N_EL_FRAME(n)); } /* Help for audio positioning */ el->last_afile = -1;}int write_edit_list(char *name, long n1, long n2, EditList *el){ FILE *fd; int i, n, num_files, oldfile, oldframe; int index[MAX_EDIT_LIST_FILES]; /* check n1 and n2 for correctness */ if(n1<0) n1 = 0; if(n2>=el->video_frames) n2 = el->video_frames-1; mjpeg_info("Write edit list: %ld %ld %s",n1,n2,name); fd = fopen(name,"w"); if(fd==0) { mjpeg_error("Can not open %s - no edit list written!",name); return -1; } fprintf(fd,"LAV Edit List\n"); fprintf(fd,"%s\n",el->video_norm=='n'?"NTSC":"PAL"); /* get which files are actually referenced in the edit list entries */ for(i=0;i<MAX_EDIT_LIST_FILES;i++) index[i] = -1; for(i=n1;i<=n2;i++) index[N_EL_FILE(el->frame_list[i])] = 1; num_files = 0; for(i=0;i<MAX_EDIT_LIST_FILES;i++) if(index[i]==1) index[i] = num_files++; fprintf(fd,"%d\n",num_files); for(i=0;i<MAX_EDIT_LIST_FILES;i++) if(index[i]>=0) fprintf(fd,"%s\n",el->video_file_list[i]); oldfile = index[N_EL_FILE(el->frame_list[n1])]; oldframe = N_EL_FRAME(el->frame_list[n1]); fprintf(fd,"%d %d ",oldfile,oldframe); for(i=n1+1;i<=n2;i++) { n = el->frame_list[i]; if(index[N_EL_FILE(n)]!=oldfile || N_EL_FRAME(n)!=oldframe+1) { fprintf(fd,"%d\n",oldframe); fprintf(fd,"%d %d ",index[N_EL_FILE(n)],N_EL_FRAME(n)); } oldfile = index[N_EL_FILE(n)]; oldframe = N_EL_FRAME(n); } n = fprintf(fd,"%d\n",oldframe); /* We did not check if all our prints succeeded, so check at least the last one */ if(n<=0) { mjpeg_error("Error writing edit list: %s", strerror(errno)); return -1; } fclose(fd); return 0;}int el_get_video_frame(uint8_t *vbuff, long nframe, EditList *el){ int res, n; if (nframe<0) nframe = 0; if (nframe>el->video_frames) nframe = el->video_frames; n = el->frame_list[nframe]; res = lav_set_video_position(el->lav_fd[N_EL_FILE(n)],N_EL_FRAME(n)); if (res<0) mjpeg_error_exit1("Error setting video position: %s",lav_strerror()); res = lav_read_frame(el->lav_fd[N_EL_FILE(n)],vbuff); if (res<0) mjpeg_error_exit1("Error reading video frame: %s",lav_strerror()); return res;}int el_get_audio_data(uint8_t *abuff, long nframe, EditList *el, int mute) { int res, n, ns0, ns1, asamps; if (!el->has_audio) return 0; if (nframe<0) nframe = 0; if (nframe>el->video_frames) nframe = el->video_frames; n = el->frame_list[nframe]; ns1 = (double)(N_EL_FRAME(n)+1)*el->audio_rate/el->video_fps; ns0 = (double) N_EL_FRAME(n) *el->audio_rate/el->video_fps; asamps = ns1-ns0; /* if mute flag is set, don't read actually, just return zero data */ if (mute) { /* TODO: A.Stevens 2000 - this looks like a potential overflow bug to me... non muted we only ever return asamps/FPS samples */ memset(abuff,0,asamps*el->audio_bps); return asamps*el->audio_bps; } if(el->last_afile!=N_EL_FILE(n) || el->last_apos!=ns0) lav_set_audio_position(el->lav_fd[N_EL_FILE(n)],ns0); res = lav_read_audio(el->lav_fd[N_EL_FILE(n)],abuff,asamps); if (res<0) mjpeg_error_exit1("Error reading audio: %s",lav_strerror()); if (res<asamps) memset(abuff+res*el->audio_bps,0,(asamps-res)*el->audio_bps); el->last_afile = N_EL_FILE(n); el->last_apos = ns1; return asamps*el->audio_bps; }int el_video_frame_data_format(long nframe, EditList *el){ int n; const char *comp; if(el->video_frames<=0) return DATAFORMAT_MJPG; /* empty editlist, return default */ if(nframe<0) nframe = 0; if(nframe>el->video_frames) nframe = el->video_frames; n = N_EL_FILE(el->frame_list[nframe]); comp = lav_video_compressor(el->lav_fd[n]); if (strncasecmp(comp,"yv12",4)==0) return DATAFORMAT_YUV420; else if (strncasecmp(comp,"yuv2",4)==0) return DATAFORMAT_YUV422; else if (strncasecmp(comp,"dv",2)==0) return DATAFORMAT_DV2; else if (strncasecmp(comp,"mjp",3)==0 || strncasecmp(comp,"jpeg",4)==0) return DATAFORMAT_MJPG; else return -1;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -