⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 editlist.c

📁 Motion JPEG编解码器源代码
💻 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 + -