/* * Some routines for handling I/O from/to different video * file formats (currently AVI, Quicktime and movtar). * * These routines are isolated here in an extra file * in order to be able to handle more formats in the future. * * Copyright (C) 2000 Rainer Johanni * * 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 #include #include #include #include #include #include #include #ifdef STRICT_CHECKING #include #endif //#include #include #ifdef USE_GDK_PIXBUF #include #endif #include #ifdef HAVE_LIBQUICKTIME #include #include #include #endif #include #include #include #define QUICKTIME_MJPG_TAG 0x6d6a7067 extern int vj_el_get_decoder_from_fourcc( const char *fourcc ); extern int AVI_errno; static int _lav_io_default_chroma = CHROMAUNKNOWN; static char video_format=' '; static int internal_error=0; #define ERROR_JPEG 1 #define ERROR_MALLOC 2 #define ERROR_FORMAT 3 #define ERROR_NOAUDIO 4 static unsigned long jpeg_field_size = 0; static unsigned long jpeg_quant_offset = 0; static unsigned long jpeg_huffman_offset = 0; static unsigned long jpeg_image_offset = 0; static unsigned long jpeg_scan_offset = 0; static unsigned long jpeg_data_offset = 0; static unsigned long jpeg_padded_len = 0; static unsigned long jpeg_app0_offset = 0; static unsigned long jpeg_app1_offset = 0; uint16_t reorder_16(uint16_t todo, int big_endian); #ifdef USE_GDK_PIXBUF static int output_scale_width = 0; static int output_scale_height = 0; static float output_fps = 25.0; static int output_yuv = 1; // 422 void lav_set_project(int w, int h, float f, int fmt) { output_scale_width = w; output_scale_height = h; output_fps = f; output_yuv = fmt; } #else void lav_set_project(int w, int h, float f, int fmt) { } #endif #define M_SOF0 0xC0 #define M_SOF1 0xC1 #define M_DHT 0xC4 #define M_SOI 0xD8 /* Start Of Image (beginning of datastream) */ #define M_EOI 0xD9 /* End Of Image (end of datastream) */ #define M_SOS 0xDA /* Start Of Scan (begins compressed data) */ #define M_DQT 0xDB #define M_APP0 0xE0 #define M_APP1 0xE1 #ifdef HAVE_LIBQUICKTIME /* put_int4: Put a 4 byte integer value into a character array as big endian number */ static void put_int4(unsigned char *buf, int val) { buf[0] = (val >> 24); buf[1] = (val >> 16); buf[2] = (val >> 8 ); buf[3] = (val ); } #endif //#ifdef SUPPORT_READ_DV2 //static int check_DV2_input(lav_file_t *lav_fd); //#endif #define TMP_EXTENSION ".tmp" /* get_int2: get a 2 byte integer value from a character array as big endian number */ static int get_int2(unsigned char *buff) { return (buff[0]*256 + buff[1]); } /* scan_jpeg: Scan jpeg data for markers, needed for Quicktime MJPA format and partly for AVI files. Taken mostly from Adam Williams' quicktime library */ static int scan_jpeg(unsigned char * jpegdata, long jpeglen, int header_only) { int marker, length; long p; jpeg_field_size = 0; jpeg_quant_offset = 0; jpeg_huffman_offset = 0; jpeg_image_offset = 0; jpeg_scan_offset = 0; jpeg_data_offset = 0; jpeg_padded_len = 0; jpeg_app0_offset = 0; jpeg_app1_offset = 0; /* The initial marker must be SOI */ if (jpegdata[0] != 0xFF || jpegdata[1] != M_SOI) return -1; /* p is the pointer within the jpeg data */ p = 2; /* scan through the jpeg data */ while(p=jpeglen) return -1; } /* Get marker code byte, swallowing any duplicate FF bytes */ while(jpegdata[p] == 0xFF) { p++; if(p>=jpeglen) return -1; } marker = jpegdata[p++]; if(p<=jpeglen-2) length = get_int2(jpegdata+p); else length = 0; /* We found a marker - check it */ if(marker == M_EOI) { jpeg_field_size = p; break; } switch(marker) { case M_SOF0: case M_SOF1: jpeg_image_offset = p-2; break; case M_DQT: if(jpeg_quant_offset==0) jpeg_quant_offset = p-2; break; case M_DHT: if(jpeg_huffman_offset==0) jpeg_huffman_offset = p-2; break; case M_SOS: jpeg_scan_offset = p-2; jpeg_data_offset = p+length; if(header_only) return 0; /* we are done with the headers */ break; case M_APP0: if(jpeg_app0_offset==0) jpeg_app0_offset = p-2; break; case M_APP1: if(jpeg_app1_offset==0) jpeg_app1_offset = p-2; break; } /* The pseudo marker as well as the markers M_TEM (0x01) and M_RST0 ... M_RST7 (0xd0 ... 0xd7) have no paramters. M_SOI and M_EOI also have no parameters, but we should never come here in that case */ if(marker == 0 || marker == 1 || (marker >= 0xd0 && marker <= 0xd7)) continue; /* skip length bytes */ if(p+length<=jpeglen) p += length; else return -1; } /* We are through parsing the jpeg data, we should have seen M_EOI */ if(!jpeg_field_size) return -1; /* Check for trailing garbage until jpeglen is reached or a new M_SOI is seen */ while(pavi_fd = 0; lav_fd->format = format; lav_fd->interlacing = interlaced ? lav_query_polarity(format):LAV_NOT_INTERLACED; lav_fd->has_audio = (asize>0 && achans>0); lav_fd->bps = (asize*achans+7)/8; lav_fd->is_MJPG = 1; lav_fd->MJPG_chroma = _lav_io_default_chroma; char fourcc[16]; int is_avi = 1; switch(format) { case 'a': case 'A': /* Open AVI output file */ veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI MJPEG"); sprintf(fourcc, "MJPG" ); break; case 'c': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI MJPEG-b"); sprintf(fourcc, "MJPB" ); break; case 'l': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI LJPEG"); sprintf(fourcc, "JPGL"); break; case 'L': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI LZO (veejay's fourcc)"); sprintf(fourcc, "MLZO" ); break; case 'v': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI VJ20 (veejay's fourcc)"); sprintf(fourcc,"VJ20"); break; case 'V': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI VJ22 (veejay's fourcc)"); sprintf(fourcc,"VJ22"); break; case 'Y': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI IYUV"); sprintf(fourcc, "IYUV" ); break; case 'P': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI YV16"); sprintf(fourcc, "YV16"); break; case 'D': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI DIV3"); sprintf(fourcc, "DIV3"); break; case 'M': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI MP4V"); sprintf(fourcc,"MP4V"); break; case 'b': case 'd': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in AVI DVSD"); sprintf(fourcc, "DVSD"); break; case 'q': case 'Q': veejay_msg(VEEJAY_MSG_DEBUG, "\tWriting output file in Quicktime MJPA/JPEG"); is_avi = 0; break; case 'x': is_avi = 0; break; } if( is_avi ) { lav_fd->avi_fd = AVI_open_output_file(filename); if(!lav_fd->avi_fd) { free(lav_fd); return NULL; } AVI_set_video(lav_fd->avi_fd, width, height, fps, fourcc ); if (asize) { if(AVI_set_audio(lav_fd->avi_fd, achans, arate, asize, WAVE_FORMAT_PCM)==-1) { veejay_msg(0, "Too many channels or invalid AVI file"); lav_close( lav_fd ); return NULL; } } return lav_fd; } else { #ifdef HAVE_LIBQUICKTIME /* open quicktime output file */ /* since the documentation says that the file should be empty, we try to remove it first */ remove(filename); lav_fd->qt_fd = quicktime_open(filename, 0, 1); if(!lav_fd->qt_fd) { veejay_msg(VEEJAY_MSG_ERROR, "\tCannot open '%s' for writing", filename); free(lav_fd); return NULL; } if(format=='q') quicktime_set_video(lav_fd->qt_fd, 1, width, height, fps, (interlaced ? QUICKTIME_MJPA : QUICKTIME_JPEG)); else quicktime_set_video(lav_fd->qt_fd,1, width,height,fps, QUICKTIME_DV ); if (asize) quicktime_set_audio(lav_fd->qt_fd, achans, arate, asize, QUICKTIME_TWOS); int has_kf = quicktime_has_keyframes( lav_fd->qt_fd, 0 ); char *copyright = quicktime_get_copyright( lav_fd->qt_fd ); char *name = quicktime_get_name( lav_fd->qt_fd ); char *info = quicktime_get_info( lav_fd->qt_fd ); veejay_msg(VEEJAY_MSG_DEBUG, "(C) %s by %s, %s, has keyframes = %d", copyright,name,info,has_kf ); return lav_fd; #else veejay_msg(0,"Quicktime not compiled in, cannot use Quicktime."); internal_error = ERROR_FORMAT; return NULL; #endif } if(lav_fd) free(lav_fd); return NULL; } int lav_close(lav_file_t *lav_file) { int ret = 0; video_format = lav_file->format; internal_error = 0; /* for error messages */ switch(video_format) { #ifdef SUPPORT_READ_DV2 case 'b': if( lav_file->dv_fd ) { veejay_msg(VEEJAY_MSG_DEBUG,"\tClosing raw dv file"); ret = rawdv_close(lav_file->dv_fd); } break; #endif #ifdef USE_GDK_PIXBUF case 'x': if( lav_file->picture ) { veejay_msg(VEEJAY_MSG_DEBUG,"\tClosing image file"); vj_picture_cleanup( lav_file->picture ); ret = 1; } break; #endif #ifdef HAVE_LIBQUICKTIME case 'q': if( lav_file->qt_fd ) { veejay_msg(VEEJAY_MSG_DEBUG, "\tClosing Quicktime file"); ret = quicktime_close( lav_file->qt_fd ); } break; #endif default: if( lav_file->avi_fd ) { veejay_msg(VEEJAY_MSG_DEBUG, "\tClosing AVI file"); ret = AVI_close(lav_file->avi_fd); } break; } if(lav_file) free(lav_file); lav_file = NULL; return ret; } long lav_bytes_remain( lav_file_t *lav_file ) { switch( lav_file->format ) { case 'a': case 'A': case 'M': case 'P': case 'D': case 'v': case 'V': case 'Y': case 'L': case 'l': case 'd': return AVI_bytes_remain( lav_file->avi_fd ); default: return 0; } return 0; } int lav_write_frame(lav_file_t *lav_file, uint8_t *buff, long size, long count) { int res, n; uint8_t *jpgdata = NULL; long jpglen = 0; #ifdef STRICT_CHECKING assert( buff != NULL ); #endif video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return -1; //rawdv, no stream writing support yet #endif /* For interlaced video insert the apropriate APPn markers */ #ifdef USE_GDK_PIXBUF if(video_format == 'x') return -1;//picture #endif if(lav_file->interlacing!=LAV_NOT_INTERLACED) { switch( lav_file->format ) { case 'a': case 'A': jpgdata = buff; jpglen = size; /* Loop over both fields */ for(n=0;n<2;n++) { /* For first field scan entire field, for second field scan the JPEG header, put in AVI1 + polarity. Be generous on errors */ res = scan_jpeg(jpgdata, size, n); if (res) { internal_error=ERROR_JPEG; return -1; } if(!jpeg_app0_offset) continue; /* APP0 marker should be at least 14+2 bytes */ if(get_int2(jpgdata+jpeg_app0_offset+2) < 16 ) continue; jpgdata[jpeg_app0_offset+4] = 'A'; jpgdata[jpeg_app0_offset+5] = 'V'; jpgdata[jpeg_app0_offset+6] = 'I'; jpgdata[jpeg_app0_offset+7] = '1'; jpgdata[jpeg_app0_offset+8] = lav_file->format=='a' ? n+1 : 2-n; /* Update pointer and len for second field */ jpgdata += jpeg_padded_len; jpglen -= jpeg_padded_len; } break; #ifdef HAVE_LIBQUICKTIME case 'q': case 'Q': jpgdata = buff; jpglen = size; /* Loop over both fields */ for(n=0;n<2;n++) { /* Scan the entire JPEG field data - APP1 marker MUST be present */ res = scan_jpeg(jpgdata,jpglen,0); if(res || !jpeg_app1_offset) { internal_error=ERROR_JPEG; return -1; } /* Length of APP1 marker must be at least 40 + 2 bytes */ if ( get_int2(jpgdata+jpeg_app1_offset+2) < 42) { internal_error=ERROR_JPEG; return -1; } /* Fill in data */ put_int4(jpgdata+jpeg_app1_offset+ 4,0); put_int4(jpgdata+jpeg_app1_offset+ 8,QUICKTIME_MJPG_TAG); put_int4(jpgdata+jpeg_app1_offset+12,jpeg_field_size); put_int4(jpgdata+jpeg_app1_offset+16,jpeg_padded_len); put_int4(jpgdata+jpeg_app1_offset+20,n==0?jpeg_padded_len:0); put_int4(jpgdata+jpeg_app1_offset+24,jpeg_quant_offset); put_int4(jpgdata+jpeg_app1_offset+28,jpeg_huffman_offset); put_int4(jpgdata+jpeg_app1_offset+32,jpeg_image_offset); put_int4(jpgdata+jpeg_app1_offset+36,jpeg_scan_offset); put_int4(jpgdata+jpeg_app1_offset+40,jpeg_data_offset); /* Update pointer and len for second field */ jpgdata += jpeg_padded_len; jpglen -= jpeg_padded_len; } break; #endif } } res = 0; /* Silence gcc */ for(n=0;nformat) { case 'a': case 'A': case 'M': case 'P': case 'D': case 'v': case 'V': case 'Y': case 'L': case 'l': case 'd': if(n==0) { res = AVI_write_frame( lav_file->avi_fd, buff, size ); } else { res = AVI_dup_frame( lav_file->avi_fd ); } break; #ifdef HAVE_LIBQUICKTIME case 'q': case 'Q': res = quicktime_write_frame( lav_file->qt_fd, buff, size, 0 ); break; #endif default: res = -1; break; } } return res; } int lav_write_audio(lav_file_t *lav_file, uint8_t *buff, long samps) { #ifdef HAVE_LIBQUICKTIME int i, j; int16_t *qt_audio = (int16_t *)buff, **qt_audion; int channels = lav_audio_channels(lav_file); qt_audion = malloc(channels * sizeof (int16_t **)); for (i = 0; i < channels; i++) qt_audion[i] = (int16_t *)malloc(samps * lav_file->bps); #endif switch(lav_file->format ) { #ifdef HAVE_LIBQUICKTIME case 'q': case 'Q': /* Deinterleave the audio into the two channels. */ for (i = 0; i < samps; i++) { for (j = 0; j < channels; j++) qt_audion[j][i] = qt_audio[(channels*i) + j]; } res = lqt_encode_audio_track(lav_file->qt_fd, qt_audion, NULL,samps,0); for (j = 0; j < channels; j++) free(qt_audion[j]); free(qt_audion); return res; break; #endif #ifdef SUPPORT_READ_DV2 case 'b': return 0; #endif #ifdef USE_GDK_PIXBUF case 'x': return 0; #endif default: return AVI_write_audio( lav_file->avi_fd, buff, samps*lav_file->bps); } return 0; } void lav_bogus_set_length( lav_file_t *lav_file , int len ) { lav_file->bogus_len = len; } int lav_bogus_video_length( lav_file_t *lav_file ) { video_format = lav_file->format; if( lav_file->format == 'x' ) return lav_file->bogus_len; return 0; } long lav_video_frames(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ switch(lav_file->format) { #ifdef SUPPORT_READ_DV2 case 'b': return rawdv_video_frames(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF case 'x': return lav_file->bogus_len; #endif #ifdef HAVE_LIBQUICKTIME case 'q': case 'Q': return quicktime_video_length(lav_file->qt_fd,0); #endif default: return AVI_video_frames( lav_file->avi_fd ); } return -1; } int lav_video_width(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ switch(lav_file->format) { #ifdef SUPPORT_READ_DV2 case 'b': return rawdv_width(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF case 'x': return output_scale_width; #endif #ifdef HAVE_LIBQUICKTIME case 'q': case 'Q': return quicktime_video_width(lav_file->qt_fd,0); #endif default: return AVI_video_width( lav_file->avi_fd); } return -1; } int lav_video_height(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ switch( lav_file->format ) { #ifdef SUPPORT_READ_DV2 case 'b': return rawdv_height( lav_file->dv_fd ); #endif #ifdef USE_GDK_PIXBUF case 'x': return output_scale_height; #endif #ifdef HAVE_LIBQUICKTIME case 'q': case 'Q': return quicktime_video_height(lav_file->qt_fd,0); #endif default: return AVI_video_height(lav_file->avi_fd); } return -1; } double lav_frame_rate(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ switch(lav_file->format) { #ifdef SUPPORT_READ_DV2 case 'b': return rawdv_fps(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF case 'x': return output_fps; #endif #ifdef HAVE_LIBQUICKTIME case 'q': case 'Q': return quicktime_frame_rate(lav_file->qt_fd,0); #endif default: return AVI_frame_rate( lav_file->avi_fd ); } return -1; } int lav_video_interlacing(lav_file_t *lav_file) { #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_interlacing(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x') return LAV_NOT_INTERLACED; #endif return lav_file->interlacing; } void lav_video_clipaspect(lav_file_t *lav_file, int *sar_w, int *sar_h) { *sar_w = lav_file->sar_w; *sar_h = lav_file->sar_h; return; } int lav_video_is_MJPG(lav_file_t *lav_file) { return lav_file->is_MJPG; } int lav_video_MJPG_chroma(lav_file_t *lav_file) { return lav_file->MJPG_chroma; } int lav_is_yuv_planar( int pix_fmt ) { switch(pix_fmt){ case PIX_FMT_YUVJ420P: case PIX_FMT_YUVJ422P: case PIX_FMT_YUVJ444P: case PIX_FMT_YUV420P: case PIX_FMT_YUV422P: case PIX_FMT_YUV444P: return 1; } return 0; } int lav_video_cmodel( lav_file_t *lav_file) { switch(lav_file->MJPG_chroma) { case CHROMA411: return PIX_FMT_YUV411P; case CHROMA420: return PIX_FMT_YUV420P; case CHROMA422: return PIX_FMT_YUV422P; case CHROMA420F: return PIX_FMT_YUVJ420P; case CHROMA422F: return PIX_FMT_YUVJ422P; case CHROMA444: return PIX_FMT_YUV444P; default: return -1; } return -1; } int lav_video_is_qt( lav_file_t *lav_file) { #ifdef HAVE_LIBQUICK_TIME if( lav_file->qt_fd) return 1; #endif return 0; } int lav_video_compressor_type(lav_file_t *lav_file) { #ifdef SUPPORT_READ_DV2 if(lav_file->format == 'b') return rawdv_compressor( lav_file->dv_fd ); #endif #ifdef USE_GDK_PIXBUF if(lav_file->format == 'x') return 0xffff; #endif #ifdef HAVE_LIBQUICKTIME if(lav_file->format == 'q' || lav_file->format == 'Q') { const char *compressor = quicktime_video_compressor(lav_file->qt_fd,0); return vj_el_get_decoder_from_fourcc( compressor ); } // return quicktime_video_compressor(lav_file->qt_fd,0); #endif return AVI_video_compressor_type( lav_file->avi_fd ); } const char *lav_video_compressor(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if( video_format == 'b' ) { const char *tmp = (const char*) strdup("dvsd"); return tmp; } #endif #ifdef USE_GDK_PIXBUF if( video_format == 'x') { const char *tmp = (const char*) strdup("PICT"); return tmp; } #endif if( video_format == 'L' ) { return (strdup("mlzo")); } #ifdef HAVE_LIBQUICKTIME if(lav_file->format == 'q' || lav_file->format == 'Q') return quicktime_video_compressor(lav_file->qt_fd,0); #endif return AVI_video_compressor(lav_file->avi_fd); } int lav_audio_channels(lav_file_t *lav_file) { if(!lav_file->has_audio) return 0; video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_audio_channels(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 0; #endif #ifdef HAVE_LIBQUICKTIME if(video_format == 'q' || video_format =='Q') return quicktime_track_channels(lav_file->qt_fd,0); #endif return AVI_audio_channels(lav_file->avi_fd); } int lav_audio_bits(lav_file_t *lav_file) { if(!lav_file->has_audio) return 0; video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_audio_bits(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x' ) return 0; #endif #ifdef HAVE_LIBQUICKTIME if(video_format == 'q'|| video_format =='Q') return quicktime_audio_bits(lav_file->qt_fd,0); #endif return (AVI_audio_bits(lav_file->avi_fd)); } long lav_audio_rate(lav_file_t *lav_file) { if(!lav_file->has_audio) return 0; video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format=='b') return rawdv_audio_rate(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 0; #endif #ifdef HAVE_LIBQUICKTIME if( video_format == 'q'|| video_format =='Q') return quicktime_sample_rate(lav_file->qt_fd,0); #endif return (AVI_audio_rate(lav_file->avi_fd)); } long lav_audio_clips(lav_file_t *lav_file) { if(!lav_file->has_audio) return 0; video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format=='b') return rawdv_audio_bps(lav_file->dv_fd); #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 0; #endif #ifdef HAVE_LIBQUICKTIME if(video_format == 'q'|| video_format == 'Q') return quicktime_audio_length(lav_file->qt_fd,0); #endif return (AVI_audio_bytes(lav_file->avi_fd)/lav_file->bps); } long lav_frame_size(lav_file_t *lav_file, long frame) { video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_frame_size( lav_file->dv_fd ); #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 1; #endif #ifdef HAVE_LIBQUICKTIME if( video_format == 'q' || video_format == 'Q') return quicktime_frame_size(lav_file->qt_fd,frame,0); #endif return (AVI_frame_size(lav_file->avi_fd,frame)); } int lav_seek_start(lav_file_t *lav_file) { video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_set_position( lav_file->dv_fd, 0 ); #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 1; #endif #ifdef HAVE_LIBQUICKTIME return quicktime_seek_start(lav_file->qt_fd); #endif return (AVI_seek_start(lav_file->avi_fd)); } int lav_set_video_position(lav_file_t *lav_file, long frame) { video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_set_position( lav_file->dv_fd, frame ); #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 1; #endif #ifdef HAVE_LIBQUICKTIME if(video_format == 'q' || video_format == 'Q') return quicktime_set_video_position(lav_file->qt_fd,(int64_t)frame,0); #endif return (AVI_set_video_position(lav_file->avi_fd,frame)); } int lav_read_frame(lav_file_t *lav_file, uint8_t *vidbuf) { video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(lav_file->format == 'b') { return rawdv_read_frame( lav_file->dv_fd, vidbuf ); } #endif #ifdef USE_GDK_PIXBUF if(lav_file->format == 'x') return -1; #endif #ifdef HAVE_LIBQUICKTIME if(lav_file->format == 'q'|| lav_file->format == 'Q') return quicktime_read_frame(lav_file->qt_fd,vidbuf,0); #endif int kf = 1; int ret = (AVI_read_frame(lav_file->avi_fd,vidbuf,&kf)); /* if(!kf) { // veejay_msg(0, "Requested frame is not a keyframe"); return ret; } */ return ret; } #ifdef USE_GDK_PIXBUF VJFrame *lav_get_frame_ptr( lav_file_t *lav_file ) { if(lav_file->format == 'x') return vj_picture_get( lav_file->picture ); return NULL; } #else uint8_t *lav_get_frame_ptr( lav_file_t *lav_file) { return NULL; } #endif int lav_is_DV(lav_file_t *lav_file) { #ifdef SUPPORT_READ_DV2 if(lav_file->format == 'b') return 1; #endif return 0; } int lav_set_audio_position(lav_file_t *lav_file, long clip) { if(!lav_file->has_audio) return 0; video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return 0; #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 0; #endif #ifdef HAVE_LIBQUICKTIME if(video_format =='q'|| video_format == 'Q') quicktime_set_audio_position(lav_file->qt_fd,clip,0); #endif return (AVI_set_audio_position(lav_file->avi_fd,clip*lav_file->bps)); } int lav_read_audio(lav_file_t *lav_file, uint8_t *audbuf, long samps) { if(!lav_file->has_audio) { internal_error = ERROR_NOAUDIO; return -1; } #ifdef SUPPORT_READ_DV2 if(video_format == 'b') return rawdv_read_audio_frame( lav_file->dv_fd, audbuf ); #endif #ifdef USE_GDK_PIXBUF if(video_format == 'x') return 0; #endif video_format = lav_file->format; internal_error = 0; /* for error messages */ #ifdef HAVE_LIBQUICKTIME if( video_format == 'q' || video_format == 'Q') { int64_t last_pos, start_pos; int res, i, j; int16_t *qt_audio = (int16_t *)audbuf, **qt_audion; int channels = lav_audio_channels(lav_file); uint8_t b0, b1; qt_audion = malloc(channels * sizeof (int16_t **)); for (i = 0; i < channels; i++) qt_audion[i] = (int16_t *)malloc(samps * lav_file->bps); start_pos = quicktime_audio_position(lav_file->qt_fd, 0); lqt_decode_audio_track(lav_file->qt_fd, qt_audion, NULL, samps, 0); last_pos = lqt_last_audio_position(lav_file->qt_fd, 0); res = last_pos - start_pos; if (res <= 0) goto out; /* Interleave the channels of audio into the one buffer provided */ for (i =0; i < res; i++) { for (j = 0; j < channels; j++) qt_audio[(channels*i) + j] = qt_audion[j][i]; } if (lav_detect_endian()) { i= 0; while (i < (2*res) ) { b0 = 0; b1 = 0; b0 = (qt_audio[i] & 0x00FF); b1 = (qt_audio[i] & 0xFF00) >> 8; qt_audio[i] = (b0 <<8) + b1; i = i +1; } } out: for (j = 0; j < channels; j++) free(qt_audion[j]); free(qt_audion); return(res); } #endif int res = AVI_read_audio( lav_file->avi_fd, audbuf, (samps * lav_file->bps) ); return res; } int lav_filetype(lav_file_t *lav_file) { return lav_file->format; } lav_file_t *lav_open_input_file(char *filename, int mmap_size) { int n; char *video_comp = NULL; unsigned char *frame = NULL; long len; int jpg_height, jpg_width, ncomps, hf[3], vf[3]; int ierr; lav_file_t *lav_fd = (lav_file_t*) vj_malloc(sizeof(lav_file_t)); if(lav_fd==0) { internal_error=ERROR_MALLOC; return 0; } /* Set lav_fd */ #ifdef HAVE_LIBQUICKTIME char *audio_comp; #endif lav_fd->avi_fd = 0; #ifdef SUPPORT_READ_DV2 lav_fd->dv_fd = 0; #endif #ifdef USE_GDK_PIXBUF lav_fd->picture = NULL; #endif lav_fd->format = 0; lav_fd->interlacing = LAV_INTER_UNKNOWN; lav_fd->sar_w = 0; /* (0,0) == unknown */ lav_fd->sar_h = 0; lav_fd->has_audio = 0; lav_fd->bps = 0; lav_fd->is_MJPG = 0; lav_fd->MJPG_chroma = CHROMAUNKNOWN; lav_fd->mmap_size = mmap_size; int ret = 0; /* open file, check if file is a file */ struct stat s; if( stat(filename, &s ) != 0 ) { if(lav_fd) free(lav_fd); veejay_msg(VEEJAY_MSG_ERROR, "Invalid file '%s'. Proper permissions?",filename); return NULL; } if(!S_ISREG( s.st_mode) ) { veejay_msg(VEEJAY_MSG_ERROR, "'%s' is not a regular file",filename); if(lav_fd) free(lav_fd); return NULL; } lav_fd->avi_fd = AVI_open_input_file(filename,1,mmap_size); if( lav_fd->avi_fd && AVI_errno == AVI_ERR_EMPTY ) { veejay_msg(VEEJAY_MSG_ERROR, "Empty AVI file"); if(lav_fd) free(lav_fd); return NULL; } else if ( lav_fd->avi_fd && AVI_errno == 0 ) { veejay_msg(VEEJAY_MSG_DEBUG, "\tFile is AVI" ); ret =1; } int alt = 0; if(lav_fd->avi_fd) { ret = 1; alt = 1; lav_fd->format = 'a'; lav_fd->has_audio = (AVI_audio_bits(lav_fd->avi_fd)>0 && AVI_audio_format(lav_fd->avi_fd)==WAVE_FORMAT_PCM); video_comp = AVI_video_compressor(lav_fd->avi_fd); if(video_comp == NULL || strlen(video_comp) <= 0) { veejay_msg(VEEJAY_MSG_ERROR, "Unable to read FOURCC from AVI"); if(lav_fd) free(lav_fd); return 0; } veejay_msg(VEEJAY_MSG_DEBUG, "\tFOURCC is %s", video_comp ); } else if( AVI_errno==AVI_ERR_NO_AVI || !lav_fd->avi_fd) { #ifdef HAVE_LIBQUICKTIME if(quicktime_check_sig(filename)) { quicktime_pasp_t pasp; int nfields, detail; lav_fd->qt_fd = quicktime_open(filename,1,0); video_format = 'q'; /* for error messages */ if (!lav_fd->qt_fd) { veejay_msg(VEEJAY_MSG_ERROR, "Unable to open quicktime file"); free(lav_fd); return 0; } else veejay_msg(VEEJAY_MSG_DEBUG, "\tOpening Quicktime file"); lav_fd->avi_fd = NULL; lav_fd->format = 'q'; video_comp = quicktime_video_compressor(lav_fd->qt_fd,0); veejay_msg(VEEJAY_MSG_DEBUG,"\tFile has fourcc '%s'", video_comp ); /* We want at least one video track */ if (quicktime_video_tracks(lav_fd->qt_fd) < 1) { veejay_msg(VEEJAY_MSG_ERROR, "At least one video track required"); lav_close(lav_fd); internal_error = ERROR_FORMAT; return 0; } /* * If the quicktime file has the sample aspect atom then use it to set * the sar values in the lav_fd structure. Hardwired (like everywhere else) * to only look at track 0. */ /* if (lqt_get_pasp(lav_fd->qt_fd, 0, &pasp) != 0) { lav_fd->sar_w = pasp.hSpacing; lav_fd->sar_h = pasp.vSpacing; }*/ /* * If a 'fiel' atom is present (not guaranteed) then use it to set the * interlacing type. */ if (lqt_get_fiel(lav_fd->qt_fd, 0, &nfields, &detail) != 0) { if (nfields == 2) { if (detail == 14 || detail == 6) lav_fd->interlacing = LAV_INTER_BOTTOM_FIRST; else if (detail == 9 || detail == 1) lav_fd->interlacing = LAV_INTER_TOP_FIRST; else veejay_msg(VEEJAY_MSG_DEBUG, "Unknown 'detail' in 'fiel' atom: %d", detail); } else lav_fd->interlacing = LAV_NOT_INTERLACED; } /* Check for audio tracks */ lav_fd->has_audio = 0; if (quicktime_audio_tracks(lav_fd->qt_fd)) { audio_comp = quicktime_audio_compressor(lav_fd->qt_fd,0); if (strncasecmp(audio_comp, QUICKTIME_TWOS,4)==0) lav_fd->has_audio = 1; else veejay_msg(VEEJAY_MSG_WARNING, "Audio compressor '%s' not supported", audio_comp ); } alt = 1; ret = 1; } else veejay_msg(VEEJAY_MSG_DEBUG, "\tNot a Quicktime file"); #endif #ifdef SUPPORT_READ_DV2 if(!alt) { ret = 0; lav_fd->dv_fd = rawdv_open_input_file(filename,mmap_size); if(lav_fd->dv_fd > 0) { lav_fd->MJPG_chroma = rawdv_sampling( lav_fd->dv_fd ); video_comp = rawdv_video_compressor( lav_fd->dv_fd ); lav_fd->format = 'b'; lav_fd->has_audio = 0; ret = 1; alt = 1; veejay_msg(VEEJAY_MSG_DEBUG, "RAW DV file '%s'", video_comp ); } else veejay_msg(VEEJAY_MSG_DEBUG, "\tNot a raw dv file"); } #endif #ifdef USE_GDK_PIXBUF if(!alt) { lav_fd->picture = vj_picture_open( (const char*) filename, output_scale_width, output_scale_height, get_ffmpeg_pixfmt(output_yuv) ); if(lav_fd->picture) { lav_fd->format = 'x'; lav_fd->has_audio = 0; lav_fd->bogus_len = (int) output_fps; video_comp = strdup( "PICT" ); ret = 1; alt = 1; veejay_msg(VEEJAY_MSG_DEBUG, "\tLoaded image file"); } else veejay_msg(VEEJAY_MSG_DEBUG, "\tNot a Image file"); } #endif } if(ret == 0 || video_comp == NULL || alt == 0) { free(lav_fd); internal_error = ERROR_FORMAT; /* Format not recognized */ veejay_msg(VEEJAY_MSG_ERROR, "Unable to load file '%s', code=%x, video=%s", filename,ret,video_comp); return 0; } lav_fd->bps = (lav_audio_channels(lav_fd)*lav_audio_bits(lav_fd)+7)/8; if(lav_fd->bps==0) lav_fd->bps=1; /* make it save since we will divide by that value */ /* if(strlen(video_comp) == 1 ) { lav_fd->MJPG_chroma = CHROMA422; lav_fd->format = 'V'; lav_fd->interlacing = LAV_NOT_INTERLACED; return lav_fd; } */ #ifdef USE_GDK_PIXBUF if(strncasecmp(video_comp, "PICT",4) == 0 ) { switch(output_yuv) { case FMT_420: case FMT_420F: lav_fd->MJPG_chroma = CHROMA420; break; case FMT_422: case FMT_422F: lav_fd->MJPG_chroma = CHROMA422; break; default: lav_fd->MJPG_chroma = CHROMAUNKNOWN; break; } lav_fd->format = 'x'; lav_fd->interlacing = LAV_NOT_INTERLACED; return lav_fd; } #endif if( strncasecmp(video_comp, "div3",4)==0 || strncasecmp(video_comp, "mp43",4)==0 || strncasecmp(video_comp, "mp42",4)==0 ) { lav_fd->MJPG_chroma = CHROMA420; lav_fd->interlacing = LAV_NOT_INTERLACED; veejay_msg(VEEJAY_MSG_WARNING, "Playing MS MPEG4v3 DivX Video. (Every frame should be an intra frame)" ); return lav_fd; } if( strncasecmp(video_comp,"mp4v",4 )==0 || strncasecmp(video_comp,"fmp4",4 )==0 || strncasecmp(video_comp,"divx",4 ) == 0 || strncasecmp(video_comp,"xvid",4 ) == 0 || strncasecmp(video_comp,"dxsd",4 ) == 0 || strncasecmp(video_comp,"mp4s",4 ) == 0 || strncasecmp(video_comp,"m4s2",4 ) == 0 ) { lav_fd->format = 'D'; lav_fd->MJPG_chroma = CHROMA420; lav_fd->interlacing = LAV_NOT_INTERLACED; veejay_msg(VEEJAY_MSG_WARNING, "Playing MPEG4 Video (Every frame should be an intra frame)"); return lav_fd; } if ( strncasecmp(video_comp,"iyuv",4)==0 || strncasecmp(video_comp,"yv12",4)==0 || strncasecmp(video_comp,"i420",4)==0) { lav_fd->MJPG_chroma = CHROMA420; lav_fd->format = 'Y'; lav_fd->interlacing = LAV_NOT_INTERLACED; return lav_fd; } if(strncasecmp(video_comp,"vj22",4)==0) { lav_fd->MJPG_chroma = CHROMA422F; lav_fd->format = 'V'; lav_fd->interlacing = LAV_NOT_INTERLACED; return lav_fd; } if(strncasecmp(video_comp,"vj20",4)==0) { lav_fd->MJPG_chroma = CHROMA420F; lav_fd->format = 'v'; lav_fd->interlacing = LAV_NOT_INTERLACED; return lav_fd; } if ( strncasecmp(video_comp,"yv16",4)==0 || strncasecmp(video_comp,"i422",4)==0 || strncasecmp(video_comp,"hfyu",4)==0) { lav_fd->MJPG_chroma = CHROMA422; lav_fd->format = 'P'; lav_fd->interlacing = LAV_NOT_INTERLACED; return lav_fd; } if( strncasecmp(video_comp, "avc1", 4 ) == 0 || strncasecmp(video_comp, "h264", 4 ) == 0 || strncasecmp(video_comp, "x264", 4 ) == 0 || strncasecmp(video_comp, "davc", 4 ) == 0 ) { lav_fd->MJPG_chroma = CHROMA420; lav_fd->interlacing = LAV_NOT_INTERLACED; return lav_fd; } if( strncasecmp( video_comp, "mlzo", 4 ) == 0 ) { lav_fd->MJPG_chroma = CHROMA422; lav_fd->interlacing = LAV_NOT_INTERLACED; return lav_fd; } if ( strncasecmp(video_comp,"dvsd",4)==0 || strncasecmp(video_comp,"dvcp",4) ==0 || strncasecmp(video_comp,"dxsd",4) == 0 || strncasecmp(video_comp, "dvp",3) == 0 || strncasecmp(video_comp, "dvhd",4) == 0 || strncasecmp(video_comp, "dv",2 ) == 0) { int gw = lav_video_height( lav_fd ); if( gw == 480 ) lav_fd->MJPG_chroma = CHROMA411; else lav_fd->MJPG_chroma = CHROMA422; lav_fd->interlacing = LAV_INTER_BOTTOM_FIRST; return lav_fd; } if( strncasecmp(video_comp, "png", 3 ) == 0 || strncasecmp(video_comp, "mpng",4) == 0 ) { lav_fd->MJPG_chroma = CHROMA420; lav_fd->interlacing = LAV_INTER_UNKNOWN; return lav_fd; } if( strncasecmp(video_comp, "svq1", 4 ) == 0 || strncasecmp(video_comp, "svq3", 4 ) == 0 || strncasecmp(video_comp, "rpza", 4 ) == 0 || strncasecmp(video_comp, "cyuv", 4 ) == 0 ) { lav_fd->MJPG_chroma = CHROMA420; lav_fd->interlacing = LAV_INTER_UNKNOWN; return lav_fd; } if ( strncasecmp(video_comp,"mjpg", 4) == 0 || strncasecmp(video_comp,"mjpa", 4) == 0 || strncasecmp(video_comp,"jpeg", 4) == 0 || strncasecmp(video_comp,"mjpb" ,4) == 0 || strncasecmp(video_comp,"sp5x", 4) == 0 || strncasecmp(video_comp,"jpgl", 4) == 0 || strncasecmp(video_comp , "jfif", 4 ) == 0 || strncasecmp(video_comp, "dmb1", 4)==0 ) { lav_fd->MJPG_chroma = CHROMA420; lav_fd->interlacing = LAV_INTER_UNKNOWN; lav_fd->is_MJPG = 1; /* Make some checks on the video source, we read the first frame for that */ ierr = 0; frame = NULL; int rolls = 5; // try to survive loading broken AVI int pos = 0; int success = 0; while( pos < rolls ) { if( frame != NULL ) { free(frame); frame = NULL; } if( lav_set_video_position(lav_fd, pos ) ) { pos++; continue; } if( (len = lav_frame_size(lav_fd, pos )) <= 0 ) { pos++; continue; } if( (frame = (unsigned char*) malloc(len)) == 0 ) { ierr = ERROR_MALLOC; break; } if( (lav_read_frame( lav_fd, frame ) <= 0 ) ) { pos ++; if( frame ) { free(frame);frame=NULL;} continue; } if( scan_jpeg(frame,len,1) ) { ierr = ERROR_JPEG; if( frame ) { free(frame);frame=NULL;} break; } success = 1; break; } if(!success) { goto ERREXIT; } else { lav_set_video_position( lav_fd, pos ); } /* if ( lav_set_video_position(lav_fd,0) ) goto ERREXIT; if ( (len = lav_frame_size(lav_fd,0)) <=0 ) goto ERREXIT; if ( (frame = (unsigned char*) malloc(len)) == 0 ) { ierr=ERROR_MALLOC; goto ERREXIT; } if ( lav_read_frame(lav_fd,frame) <= 0 ) goto ERREXIT; if ( lav_set_video_position(lav_fd,0) ) goto ERREXIT; if( scan_jpeg(frame, len, 1) ) { ierr=ERROR_JPEG; goto ERREXIT; } /* We have to look to the JPEG SOF marker for further information The SOF marker has the following format: FF C0 len_hi len_lo data_precision height_hi height_lo width_hi width_lo num_components And then 3 bytes for each component: Component id H, V sampling factors (as nibbles) Quantization table number */ /* Check if the JPEG has the special 4:2:2 format needed for some HW JPEG decompressors (the Iomega Buz, for example) */ ncomps = frame[jpeg_image_offset + 9]; if(ncomps==3) { for(n=0;n<3;n++) { hf[n] = frame[jpeg_image_offset + 10 + 3*n + 1]>>4; vf[n] = frame[jpeg_image_offset + 10 + 3*n + 1]&0xf; } /* Identify chroma sub-sampling format only 420 and 422 supported at present...*/ if( hf[0] == 2*hf[1] && hf[0] == 2*hf[2] ) { if( vf[0] == vf[1] && vf[0] == vf[2] ) { lav_fd->MJPG_chroma = CHROMA422; } else if( vf[0] == 2*vf[1] && vf[0] == 2*vf[2] ) { lav_fd->MJPG_chroma = CHROMA420; } else { lav_fd->MJPG_chroma = CHROMAUNKNOWN; } } else { lav_fd->MJPG_chroma = CHROMAUNKNOWN; } } // ncomps /* Check if video is interlaced */ /* height and width are encoded in the JPEG SOF marker at offsets 5 and 7 */ jpg_height = get_int2(frame + jpeg_image_offset + 5); jpg_width = get_int2(frame + jpeg_image_offset + 7); if( strncasecmp( frame + 6, "LAVC", 4 ) == 0 ) { int pf = detect_pixel_format_with_ffmpeg( filename ); switch(pf) { case PIX_FMT_YUV422P: lav_fd->MJPG_chroma = CHROMA422;break; case PIX_FMT_YUVJ422P:lav_fd->MJPG_chroma = CHROMA422F;break; case PIX_FMT_YUV420P: lav_fd->MJPG_chroma = CHROMA420;break; case PIX_FMT_YUVJ420P: lav_fd->MJPG_chroma = CHROMA420F;break; case PIX_FMT_YUV444P: lav_fd->MJPG_chroma = CHROMA444;break; default: pf = -1; break; } if( pf >= 0 ) { lav_fd->interlacing = LAV_NOT_INTERLACED; if(frame) free(frame); return lav_fd; } } /* check height */ if( jpg_height == lav_video_height(lav_fd)) { lav_fd->interlacing = LAV_NOT_INTERLACED; } else if ( jpg_height == lav_video_height(lav_fd)/2 ) { /* Video is interlaced */ if(lav_fd->format == 'a') { /* Check the APP0 Marker, if present */ if(jpeg_app0_offset && get_int2(frame + jpeg_app0_offset + 2) >= 5 && strncasecmp((char*)(frame + jpeg_app0_offset + 4),"AVI1",4)==0 ) { if (frame[jpeg_app0_offset+8]==1) { lav_fd->interlacing = LAV_INTER_TOP_FIRST; } else { lav_fd->interlacing = LAV_INTER_BOTTOM_FIRST; } } else { /* There is no default, it really depends on the application which produced the AVI */ lav_fd->interlacing = LAV_INTER_UNKNOWN; } lav_fd->format = lav_fd->interlacing == LAV_INTER_BOTTOM_FIRST ? 'A' : 'a'; } // end of interlaced } else { ierr=ERROR_JPEG; goto ERREXIT; } if(frame) free(frame); return lav_fd; } ierr = ERROR_FORMAT; veejay_msg(VEEJAY_MSG_ERROR, "Unrecognized format '%s'", video_comp); ERREXIT: lav_close(lav_fd); if(frame) free(frame); internal_error = ierr; veejay_msg(VEEJAY_MSG_ERROR, "%s", lav_strerror()); return 0; } /* Get size of first field of for a data array containing (possibly) two jpeg fields */ int lav_get_field_size(uint8_t * jpegdata, long jpeglen) { int res; res = scan_jpeg(jpegdata,jpeglen,0); if(res<0) return jpeglen; /* Better than nothing */ /* we return jpeg_padded len since this routine is used for field exchange where alignment might be important */ return jpeg_padded_len; } static char error_string[4096]; const char *lav_strerror(void) { switch(internal_error) { case ERROR_JPEG: sprintf(error_string,"Internal: broken JPEG format"); internal_error = 0; return error_string; case ERROR_MALLOC: sprintf(error_string,"Internal: Out of memory"); internal_error = 0; return error_string; case ERROR_FORMAT: sprintf(error_string,"Input file format not recognized"); internal_error = 0; return error_string; case ERROR_NOAUDIO: sprintf(error_string,"Trying to read audio from a video only file"); internal_error = 0; return error_string; } switch(video_format) { case 'a': case 'A': case 'Y': case 'v': case 'V': case 'M': case 'P': case 'L': case 'D': return AVI_strerror(); default: /* No or unknown video format */ sprintf(error_string,"No or unknown video format"); return error_string; } } /* static int check_DV2_input(lav_file_t *lav_fd) { int ierr = 0; double len = 0; unsigned char *frame = NULL; lav_fd->is_MJPG = 0; if ( lav_set_video_position(lav_fd,0) ) goto ERREXIT; if ( (len = lav_frame_size(lav_fd,0)) <=0 ) goto ERREXIT; if ( (frame = (unsigned char*) malloc(len)) == 0 ) { ierr=ERROR_MALLOC; goto ERREXIT; } if ( lav_read_frame(lav_fd,frame) <= 0 ) goto ERREXIT; { dv_decoder_t *decoder = dv_decoder_new(0,0,0); dv_parse_header(decoder, frame); switch (decoder->system) { case e_dv_system_525_60: if (dv_format_wide(decoder)) { lav_fd->sar_w = 40; lav_fd->sar_h = 33; } else { lav_fd->sar_w = 10; lav_fd->sar_h = 11; } break; case e_dv_system_625_50: if (dv_format_wide(decoder)) { lav_fd->sar_w = 118; lav_fd->sar_h = 81; } else { lav_fd->sar_w = 59; lav_fd->sar_h = 54; } break; default: lav_fd->sar_w = 0; lav_fd->sar_h = 0; break; } veejay_msg(VEEJAY_MSG_DEBUG, "DV System %s (sar w %d sar h %d)", (decoder->system == e_dv_system_525_60 ? "525-60" : ( decoder->system == e_dv_system_625_50 ? "625-50" : "unknown!")),lav_fd->sar_w,lav_fd->sar_h); dv_decoder_free(decoder); } if ( lav_set_video_position(lav_fd,0) ) goto ERREXIT; return 0; ERREXIT: lav_close(lav_fd); if(frame) free(frame); if (ierr) internal_error = ierr; return 1; } */ int lav_fileno(lav_file_t *lav_file) { int res; video_format = lav_file->format; switch(lav_file->format) { #ifdef HAVE_LIBQUICKTIME case 'q': case 'Q': { #if ( LQT_CODEC_API_VERSION & 0xffff ) > 6 res = lqt_fileno( (quicktime_t*) lav_file->qt_fd ); #else quicktime_t *q = lav_file->qt_fd; res = (int) fileno( (quicktime_t*) q->stream ); #endif } break; #endif default: res = AVI_fileno(lav_file->avi_fd); } return res; } /* We need this to reorder the 32 bit values for big endian systems */ uint32_t reorder_32(uint32_t todo, int big_endian) { unsigned char b0, b1, b2, b3; unsigned long reversed; if( big_endian ) { b0 = (todo & 0x000000FF); b1 = (todo & 0x0000FF00) >> 8; b2 = (todo & 0x00FF0000) >> 16; b3 = (todo & 0xFF000000) >> 24; reversed = (b0 << 24) + (b1 << 16) + (b2 << 8) +b3; return reversed; } return todo; } int lav_detect_endian (void) { unsigned int fred; char *pfred; fred = 2 | (1 << (sizeof(int)*8-8)); pfred = (char *)&fred; if (*pfred == 1) return 1; else if(*pfred == 2) return 0; else return -1; }