/** \fn ADM_copyFile */ uint8_t ADM_copyFile(const char *source, const char *target) { FILE *fin=ADM_fopen(source,"rb"); if(!fin) { ADM_error("Cannot open %s for reading\n",source); return false; } FILE *fout=ADM_fopen(target,"wb"); if(!fout) { fclose(fin); ADM_error("Cannot open %s for writting\n",target); return false; } uint8_t buffer[1024]; while(!feof(fin)) { int r=fread(buffer,1,1024,fin); fwrite(buffer,1,r,fout); if(r!=1024) break; } fclose(fin); fclose(fout); return true; }
uint8_t asfHeader::open(const char *name) { _fd=ADM_fopen(name,"rb"); if(!_fd) { GUI_Error_HIG("File Error.","Cannot open file\n"); return 0; } myName=ADM_strdup(name); if(!getHeaders()) { return 0; } ADM_info("Stream Video: index=%d, sid=%d\n",(int)_videoIndex,(int)_videoStreamId); for(int i=0;i<_nbAudioTrack;i++) ADM_info("Stream Audio: index=%d, sid=%d\n", (int)_allAudioTracks[i].streamIndex,(int)_allAudioTracks[i].streamIndex); buildIndex(); fseeko(_fd,_dataStartOffset,SEEK_SET); _packet=new asfPacket(_fd,_nbPackets,_packetSize,&readQueue,&storageQueue,_dataStartOffset); curSeq=1; for(int i=0;i<_nbAudioTrack;i++) { _audioAccess[i]=new asfAudioAccess(this,i); _audioStreams[i]=ADM_audioCreateStream(&(_allAudioTracks[i].wavHeader), _audioAccess[i]); } if(!nbImage) { ADM_error("No image found \n"); return 0; } return 1; }
ADM_audioAccessFile::ADM_audioAccessFile(const char *fileName,int offset) { _offset=offset; fileLength=ADM_fileSize(fileName)-offset; _fd=ADM_fopen(fileName,"rb"); ADM_assert(_fd); }
/** \fn detectTs \brief returns true if the file seems to be mpeg PS */ bool detectTs(const char *file) { uint8_t buffer[PROBE_SIZE]; uint32_t bufferSize; uint32_t nbPacket,nbMatch=0; FILE *f=ADM_fopen(file,"rb"); if(!f) return false; bufferSize=fread(buffer,1,PROBE_SIZE,f); fclose(f); // Do a simple check by checking we have 0x47....0x47 several time in a raw if(true==checkMarker(buffer,bufferSize,TS_PACKET_LEN)) { ADM_info("[TS Demuxer] 188 bytes packet detected\n"); return true; } // Do a simple check by checking we have 0x47....0x47 several time in a raw if(true==checkMarker(buffer,bufferSize,TS_PACKET_LEN+4)) { ADM_info("[TS Demuxer] 192 bytes packet detected\n"); return true; } ADM_info("[TS Demuxer] Not a TS file\n"); return false; }
/** \fn addFile \brief Load or append a file. The file type is determined automatically and the ad-hoc video decoder is spawned @param name: filename @return 1 on success, 0 on failure */ bool ADM_Composer::addFile (const char *name) { uint8_t ret = 0; aviInfo info; uint32_t magic; _VIDEOS video; bool avisynth_used = false; if(!strcmp(name, AVS_PROXY_DUMMY_FILE)) { magic=0; avisynth_used = true; } else { FILE *f=ADM_fopen(name,"r"); uint8_t buffer[4]; if(!f) return 0; fread(buffer,4,1,f); fclose(f); magic=(buffer[3]<<24)+(buffer[2]<<16)+(buffer[1]<<8)+(buffer[0]); } // First find the demuxer.... video._aviheader=ADM_demuxerSpawn(magic,name); if(!video._aviheader) { char str[512+1]; snprintf(str,512,QT_TR_NOOP("Cannot find a demuxer for %s"), name); str[512] = '\0'; GUI_Error_HIG(str,NULL); return false; } // use "file name" to share the port number (using little endian) if(avisynth_used) { uint32_t portValue = 0; bool useCmdLine = A_getCommandLinePort(portValue); if (!useCmdLine) if(!prefs->get(AVISYNTH_AVISYNTH_DEFAULTPORT, &portValue)) portValue = 9999; bool askPortAvisynth = false; prefs->get(AVISYNTH_AVISYNTH_ALWAYS_ASK, &askPortAvisynth); if(askPortAvisynth) { uint32_t localPort = 0; if (useCmdLine || !prefs->get(AVISYNTH_AVISYNTH_LOCALPORT, &localPort) || localPort == 0) localPort = portValue; if (UI_askAvisynthPort(localPort)) { portValue = localPort; prefs->set(AVISYNTH_AVISYNTH_LOCALPORT, localPort); } } uint8_t dummy[] = { portValue , portValue >> 8}; ret = video._aviheader->open((char *)dummy); } else
extern "C" uint32_t probe(uint32_t magic, const char *fileName) { char *index=(char *)alloca(strlen(fileName)+6); int count=0; printf("[TS Demuxer] Probing...\n"); if( !detectTs(fileName)) { printf(" [TS Demuxer] Not a ts file\n"); return false; } sprintf(index,"%s.idx2",fileName); again: if(ADM_fileExist(index)) { printf(" [TS Demuxer] There is an index for that file \n"); FILE *f=ADM_fopen(index,"rt"); char signature[10]; fread(signature,4,1,f); signature[4]=0; fclose(f); if(!strcmp(signature,"PSD1")) { // Check if it is a valid index for us... indexFile indexFile; char *type; if(!indexFile.open(index)) { printf("[tsDemux] Cannot open index file %s\n",index); indexFile.close(); return false; } if(!indexFile.readSection("System")) { printf("[tsDemux] Cannot read system section\n"); indexFile.close(); return false; } type=indexFile.getAsString("Type"); if(!type || type[0]!='T') { printf("[TsDemux] Incorrect or not found type\n"); indexFile.close(); return false; } return 50; } printf("[TSDemuxer] Not a valid index\n"); return false; } if(count) return false; printf("[TSDemuxer] Analyzing file..\n"); count++; if(true==tsIndexer(fileName)) goto again; printf("[TSDemuxer] Failed..\n"); return 0; }
/** \fn ADM_fileSize \brief return filesize, -1 on error */ int64_t ADM_fileSize(const char *file) { FILE *f=ADM_fopen(file,"r"); if(!f) return -1; fseeko(f,0,SEEK_END); int64_t v=ftello(f); fclose(f); return v; }
uint8_t wtvHeader::open(const char *name) { _fd=ADM_fopen(name,"rb"); if(!_fd) { GUI_Error_HIG("File Error.","Cannot open file\n"); return 0; } return false; for(int i=0;i<_nbAudioTrack;i++) { _audioAccess[i]=new wtvAudioAccess(this,i); _audioStreams[i]=ADM_audioCreateStream(&(_allAudioTracks[i].wavHeader), _audioAccess[i]); } return 1; }
/** \fn create_edAudioExternal */ ADM_edAudioTrackExternal *create_edAudioExternal(const char *name) { #define EXTERNAL_PROBE_SIZE (1024*1024) // Identify file type uint8_t buffer[EXTERNAL_PROBE_SIZE]; FILE *f=ADM_fopen(name,"rb"); if(!f) { ADM_warning("Cannot open %s\n",name); return NULL; } fread(buffer,1,EXTERNAL_PROBE_SIZE,f); fclose(f); WAVHeader hdr; uint32_t offset; if(false==ADM_identifyAudioStream(EXTERNAL_PROBE_SIZE,buffer,hdr,offset)) { ADM_warning("Cannot identify external audio track\n"); return NULL; } // Try to create an access for the file... switch(hdr.encoding) { case WAV_PCM: case WAV_AC3: case WAV_MP3: break; default: ADM_warning("Unsupported external audio tracks \n"); return NULL; break; } ADM_info("Found external audio track, encoding =%d offset=%d\n",(int)hdr.encoding,(int)offset); // create access ADM_audioAccessFile *access=new ADM_audioAccessFile(name,offset); // create ADM_edAudioTrack ADM_edAudioTrackExternal *external=new ADM_edAudioTrackExternal(name, &hdr,access); if(!external->create()) { delete external; external=NULL; ADM_warning("Failed to create external track from %s\n",name); return NULL; } // done! return external; }
/** * * @param name * @return */ bool ADM_ebml_file::open(const char *name) { fp=ADM_fopen(name,"rb"); if(!fp) { aprintf("[EBML FILE] Failed to open <%s>\n",name); return 0; } _root=this; _close=1; fseeko(fp,0,SEEK_END); _begin=0; _fileSize=_size=ftello(fp); fseeko(fp,0,SEEK_SET); return 1; }
/** * \fn call_scriptEngine * @param scriptFile */ void call_scriptEngine(const char *scriptFile) { char *fullpath=ADM_PathCanonize(scriptFile); FILE *fd=ADM_fopen(fullpath,"r"); if(!fd) { if(errno == EACCES) { GUI_Error_HIG(QT_TRANSLATE_NOOP("adm", "Permission Error"), QT_TRANSLATE_NOOP("adm", "Cannot open script \"%s\"."), fullpath); } if(errno == ENOENT) { GUI_Error_HIG(QT_TRANSLATE_NOOP("adm", "File Error"), QT_TRANSLATE_NOOP("adm", "Script \"%s\" does not exist."), fullpath); } return; } std::vector<IScriptEngine*> engines = getScriptEngines(); std::string root,ext; ADM_PathSplit(std::string(fullpath),root,ext); if(engines.size() == 1) { A_parseScript(engines[0],fullpath); if(avifileinfo) { A_Rewind(); UI_setMarkers(video_body->getMarkerAPts(),video_body->getMarkerBPts()); } return; } for (int i = 0; i < engines.size(); i++) { if (!engines[i]->defaultFileExtension().compare(ext)) { A_parseScript(engines[i],fullpath); A_Rewind(); UI_setMarkers(video_body->getMarkerAPts(),video_body->getMarkerBPts()); return; } } ADM_warning("Unable to appropriate script engine for script file\n"); }
extern "C" uint32_t ADM_PLUGIN_EXPORT probe(uint32_t magic, const char *fileName) { if (fourCC::check (magic, (uint8_t *) "RIFF")) { // Make sure it is really an avi... FILE *f=ADM_fopen(fileName,"r"); if(!f) return 0; uint8_t buf[12]; fread(buf,12,1,f); fclose(f); if(fourCC::check(buf+8,(uint8_t *)"AVI ")) { printf (" [openDML] AVI/OpenDML file detected...\n"); return 100; } } printf (" [openDML] Cannot open that\n"); return 0; }
void A_saveScript(IScriptEngine* engine, const char* name) { IScriptWriter *writer = engine->createScriptWriter(); ADM_ScriptGenerator generator(video_body, writer); std::stringstream stream(std::stringstream::in | std::stringstream::out); std::string fileName = name; generator.generateScript(stream); delete writer; if (fileName.rfind(".") == std::string::npos) { fileName += "." + engine->defaultFileExtension(); } FILE *file = ADM_fopen(fileName.c_str(), "wt"); string script = stream.str(); ADM_fwrite(script.c_str(), script.length(), 1, file); ADM_fclose(file); }
/** \fn detectPs \brief returns true if the file seems to be mpeg PS */ bool detectPs(const char *file) { uint32_t bufferSize; uint32_t nbPacket,nbMatch=0; FILE *f=ADM_fopen(file,"rb"); if(!f) return false; uint8_t *buffer = new uint8_t[PROBE_SIZE]; bufferSize=fread(buffer,1,PROBE_SIZE,f); fclose(f); nbPacket=bufferSize/2300; uint8_t *head,*tail; head=buffer; tail=buffer+bufferSize; uint8_t code; uint32_t offset; bool r = false; // Is it a Seq Start ? if(!buffer[0] && !buffer[1] && buffer[2]==1 && buffer[3]==0xba) { printf("Starts with SEQUENCE_START, probably MpegPS\n"); delete[] buffer; return true; } while(ADM_findMpegStartCode(head,tail,&code,&offset)) { head+=offset; if(code==0xE0) nbMatch++; } printf(" match :%d / %d (probeSize:%d)\n",nbMatch,nbPacket,bufferSize); if (nbMatch * 10 > nbPacket * 2) { r = true; } delete[] buffer; return r; }
void FileSel_ReadWrite(SELFILE_CB *cb, int rw, const char *name, const char *actual_workbench_file) { if(name) { if(cb) { FILE *fd; fd=ADM_fopen(name,"rb"); if(rw==0) // read { // try to open it.. if(!fd) { GUI_Error_HIG(QT_TRANSLATE_NOOP("filesel","File error"), QT_TRANSLATE_NOOP("filesel","Cannot open \"%s\"."), name); return; } } else // write { if(fd){ struct stat buf; int fdino; ADM_fclose(fd); char msg[300]; snprintf(msg, 300, QT_TRANSLATE_NOOP("filesel","%s already exists.\n\nDo you want to replace it?"), ADM_GetFileName(name)); if(!GUI_Question(msg)) return; /* ** JSC Fri Feb 10 00:07:30 CET 2006 ** compare existing output file inode against each current open files inode ** i'm ignoring st_dev, so we may get false positives ** i'm testing until fd=1024, should be MAXFD computed by configure ** keep in mind: ** you can overwrite .idx files, they are loaded into memory and closed soon ** you cannot overwrite segment data files, all files are kept open and ** are detected here */ #ifndef _WIN32 if( stat(name,&buf) == -1 ){ fprintf(stderr,"stat(%s) failed\n",name); return; } #endif fdino = buf.st_ino; for(int i=0;i<1024;i++){ if( fstat(i,&buf) != -1 ){ if( buf.st_ino == fdino ){ char str[512]; snprintf(str,512,"File \"%s\" exists and is opened by Avidemux",name); GUI_Error_HIG(str, QT_TRANSLATE_NOOP("filesel","It is possible that you are trying to overwrite an input file!")); return; } } } /* ** compare output file against actual EMCAscript file ** need to stat() to avoid symlink (/home/x.js) vs. real file (/export/home/x.js) case */ if( actual_workbench_file ){ if( stat(actual_workbench_file,&buf) != -1 ){ if( buf.st_ino == fdino ){ char str[512]; snprintf(str,512,"File \"%s\" exists and is the actual ECMAscript file",name); GUI_Error_HIG(str,QT_TRANSLATE_NOOP("filesel","It is possible that you are trying to overwrite an input file!")); return; } } } } // check we have right access to it fd=ADM_fopen(name,"wb"); if(!fd) { GUI_Error_HIG(QT_TRANSLATE_NOOP("filesel","Cannot write the file"),QT_TRANSLATE_NOOP("filesel", "No write access to \"%s\"."), name); return; } } ADM_fclose(fd); cb(name); } // no callback -> return value } }
/** \fn saveAsJpg \brief save current image into filename, into jpg format */ bool ADMImage::saveAsJpgInternal(const char *filename) { AVCodecContext *context=NULL; AVFrame *frame=NULL; bool result=false; AVCodec *codec=NULL; int r=0; ADM_byteBuffer byteBuffer; frame=av_frame_alloc(); if(!frame) { printf("[saveAsJpg] Cannot allocate frame\n"); goto jpgCleanup; } codec=avcodec_find_encoder(AV_CODEC_ID_MJPEG); if(!codec) { printf("[saveAsJpg] Cannot allocate codec\n"); goto jpgCleanup; } context=avcodec_alloc_context3(codec); if(!context) { printf("[saveAsJpg] Cannot allocate context\n"); goto jpgCleanup; } context->pix_fmt =AV_PIX_FMT_YUV420P; context->strict_std_compliance = -1; context->time_base.den=1; context->time_base.num=1; context->width=_width; context->height=_height; context->flags |= CODEC_FLAG_QSCALE; r=avcodec_open2(context, codec, NULL); if(r<0) { printf("[saveAsJpg] Cannot mix codec and context\n"); ADM_dealloc (context); return false; } // Setup our image & stuff.... frame->width=_width; frame->height=_height; frame->format=AV_PIX_FMT_YUV420P; frame->linesize[0] = GetPitch(PLANAR_Y); frame->linesize[2] = GetPitch(PLANAR_U); frame->linesize[1] = GetPitch(PLANAR_V); frame->data[0] = GetWritePtr(PLANAR_Y); frame->data[2] = GetWritePtr(PLANAR_U); frame->data[1] = GetWritePtr(PLANAR_V); // Grab a temp buffer // Encode! frame->quality = (int) floor (FF_QP2LAMBDA * 2+ 0.5); byteBuffer.setSize(_width*_height*4); AVPacket pkt; av_init_packet(&pkt); int gotSomething; pkt.size=_width*_height*4; pkt.data=byteBuffer.at(0); r=avcodec_encode_video2(context,&pkt,frame,&gotSomething); if(r || !gotSomething) { ADM_error("[jpeg] Error %d encoding video\n",r); goto jpgCleanup; } // Ok now write our file... { FILE *f=ADM_fopen(filename,"wb"); if(f) { fwrite(byteBuffer.at(0),pkt.size,1,f); fclose(f); result=true; }else { printf("[saveAsJpeg] Cannot open %s for writing!\n",filename); } } // Cleanup jpgCleanup: if(context) { avcodec_close (context); av_free (context); context=NULL; } if(frame) { av_frame_free(&frame); frame=NULL; } return result; }
/** \fn saveAsPngInternal \brief save current image into filename in PNG format */ bool ADMImage::saveAsPngInternal(const char *filename) { AVCodecContext *context=NULL; AVFrame *frame=NULL; AVCodec *codec=NULL; bool result=false; int sz=_width*_height*3, r=0; uint8_t *out; int xss[3], xds[3]; uint8_t *xsp[3], *xdp[3]; ADMColorScalerSimple converter(_width, _height, ADM_COLOR_YV12, ADM_COLOR_RGB24); ADM_byteBuffer byteBuffer; frame=av_frame_alloc(); if(!frame) { ADM_error("Cannot allocate frame\n"); goto __cleanup; } codec=avcodec_find_encoder(AV_CODEC_ID_PNG); if(!codec) { ADM_error("Cannot allocate codec\n"); goto __cleanup; } context=avcodec_alloc_context3(codec); if(!context) { ADM_error("Cannot allocate context\n"); goto __cleanup; } context->pix_fmt=AV_PIX_FMT_RGB24; context->strict_std_compliance = -1; context->time_base.den=1; context->time_base.num=1; context->width=_width; context->height=_height; r=avcodec_open2(context, codec, NULL); if(r<0) { ADM_error("Cannot combine codec and context\n"); ADM_dealloc(context); return false; } // swap U & V planes first out=(uint8_t *)ADM_alloc(sz); xss[0] = this->GetPitch(PLANAR_Y); xss[1] = this->GetPitch(PLANAR_V); xss[2] = this->GetPitch(PLANAR_U); xsp[0] = this->GetReadPtr(PLANAR_Y); xsp[1] = this->GetReadPtr(PLANAR_V); xsp[2] = this->GetReadPtr(PLANAR_U); xds[0] = _width*3; xds[1] = xds[2] = 0; xdp[0] = out; xdp[1] = xdp[2] = NULL; // convert colorspace converter.convertPlanes(xss,xds,xsp,xdp); // setup AVFrame frame->width = _width; frame->height = _height; frame->format = AV_PIX_FMT_RGB24; frame->linesize[0] = _width*3; frame->linesize[1] = 0; frame->linesize[2] = 0; frame->data[0] = out; frame->data[1] = NULL; frame->data[2] = NULL; // Grab a temp buffer byteBuffer.setSize(sz); // Encode AVPacket pkt; av_init_packet(&pkt); int gotSomething; pkt.size=sz; pkt.data=byteBuffer.at(0); r=avcodec_encode_video2(context,&pkt,frame,&gotSomething); if(r || !gotSomething) { ADM_error("Error %d encoding image\n",r); goto __cleanup; } // Ok now write our file... { FILE *f=ADM_fopen(filename,"wb"); if(f) { fwrite(byteBuffer.at(0),pkt.size,1,f); fclose(f); result=true; }else { ADM_error("Cannot open %s for writing!\n",filename); } } __cleanup: // Cleanup if(context) { avcodec_close(context); av_free(context); context=NULL; } if(frame) { av_frame_free(&frame); frame=NULL; } return result; }
/* Open one file, probe to see if there is several file with contiguous name and handle them as one big file if that's the case If multi is set to probe, return value will be APPEND if there is several files, dont_append if one if multi is set to dont_append, file won't be auto appended even if they exist */ uint8_t fileParser::open( const char *filename,FP_TYPE *multi ) { uint32_t decimals = 0; // number of decimals char *left = NULL, *right = NULL; // parts of filename (after splitting) uint8_t count = 0; // number of follow-ups uint32_t base=0; bool splitFile=false; // int i = 0; // index (general use) if(*multi!=FP_DONT_APPEND) { aprintf("Checking if there are several files...\n"); splitFile=ADM_splitSequencedFile(filename, &left, &right,&decimals,&base); if(splitFile) { aprintf("left:<%s>, right=<%s>,base=%" PRIu32",digit=%" PRIu32"\n",left,right,base,decimals); }else { aprintf("No.\n"); } } // ____________________ // Single loading // ____________________ if( false ==splitFile ) { fdIo newFd; aprintf( "\nSimple loading: \n" ); _curFd = 0; FILE *f=NULL; // open file if(! (f = ADM_fopen(filename, "rb")) ) { return 0; } newFd.file=f; // calculate file-size fseeko( f, 0, SEEK_END ); newFd.fileSize = ftello( f ); fseeko( f, 0, SEEK_SET ); newFd.fileSizeCumul=0; _size=newFd.fileSize; listOfFd.append(newFd); aprintf( " file: %s, size: %" PRIu64"\n", filename, newFd.fileSize ); aprintf( " found 1 files \n" ); aprintf( "Done \n" ); return 1; } // ____________________ // Multi loading // ____________________ uint32_t tabSize; std::string leftPart(left); std::string rightPart(right); delete [] left; delete [] right; left=NULL; right=NULL; aprintf( "\nAuto adding: \n" ); uint32_t current=base; _curFd = 0; uint64_t total=0; // build match string char match[16]; match[0]='%'; match[1]='0'; sprintf(match+2,"%d",decimals); // snprintf instead ... strcat(match,"d"); match[15]=0; aprintf("Using %s as match string\n",match); char number[16]; while(1) { sprintf(number,match,current); std::string middle(number); std::string outName=leftPart+middle+rightPart; aprintf("Checking %s\n",outName.c_str()); // open file FILE *f= ADM_fopen(outName.c_str(), "rb"); if(!f) { // we need at least one file! if( !count ) { return 0; } else { printf( " file: %s not found. \n", outName.c_str() ); break; } } // calculate file-size fdIo myFd; myFd.file=f; myFd.fileSize=ADM_fileSize(outName.c_str()); myFd.fileSizeCumul = total; total+= myFd.fileSize; aprintf( " file %d: %s, size: %" PRIu64"\n", (count + 1), outName.c_str(), myFd.fileSize ); listOfFd.append(myFd); count++; current++; } _size=total; // clean up if(*multi==FP_PROBE) { if(count>1) *multi=FP_APPEND; // else *multi=FP_DONT_APPEND; } aprintf( " found %d files \n", count ); aprintf( "Done \n" ); return 1; } // fileParser::open()
/** \fn open */ uint8_t OpenDMLHeader::open(const char *name) { uint8_t badAvi=0; uint32_t rd; printf("** opening OpenDML files **"); _fd=ADM_fopen(name,"rb"); if(!_fd) { printf("\n cannot open %s \n",name); return 0; } myName=ADM_strdup(name); #define CLR(x) memset(& x,0,sizeof( x)); CLR( _videostream); CLR( _mainaviheader); _isvideopresent=1; _isaudiopresent=0; _nbTrack=0; riffParser *parser=new riffParser(name); if(MKFCC('R','I','F','F')!=(rd=parser->read32())) { printf("Not riff\n");badAvi=1; printf("%x != %x\n",rd,MKFCC('R','I','F','F')); } parser->read32(); if(MKFCC('A','V','I',' ')!=parser->read32()) { printf("Not Avi\n");badAvi=1; } if(!badAvi) { walk(parser); } delete parser; aprintf("Found %d tracks\n:-----------\n",_nbTrack); // check if it looks like a correct avi if(!_nbTrack) badAvi=1; // if we are up to here -> good avi :) if(badAvi) { printf("FAIL\n"); return 0; } // now read up each parts... //____________________________ #define DUMP_TRACK(i) aprintf(" at %"PRIu64" (%"PRIx64") size : %"PRIu64" (%"PRIx64")\n", \ _Tracks[i].strh.offset,\ _Tracks[i].strh.offset,\ _Tracks[i].strh.size,\ _Tracks[i].strh.size); for(uint32_t i=0;i<_nbTrack;i++) { DUMP_TRACK(i); } uint32_t vidTrack=0xff; // search wich track is the video one // and load it to _videoheader for(uint32_t i=0;i<_nbTrack;i++) { fseeko(_fd,_Tracks[i].strh.offset,SEEK_SET); if(_Tracks[i].strh.size!=sizeof(_videostream)) { printf("[AVI]Mmm(1) we have a bogey here, size mismatch : %"PRIu64"\n",_Tracks[i].strh.size); printf("[AVI]expected %d\n",(int)sizeof(_videostream)); if(_Tracks[i].strh.size<sizeof(_videostream)-8) // RECT is not mandatory { GUI_Error_HIG(QT_TR_NOOP("Malformed header"), NULL); return 0; } printf("[AVI]Trying to continue anyway\n"); } fread(&_videostream,sizeof(_videostream),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_AviStreamHeader(&_videostream); #endif if(_videostream.fccType==MKFCC('v','i','d','s')) { vidTrack=i; printf("Video track is %u\n",i); break; } } if(0xff==vidTrack) { printf("Could not identify video track!"); return 0; } // then bih stuff int32_t extra; // _fd=fopen(name,"rb"); fseeko(_fd,_Tracks[vidTrack].strf.offset,SEEK_SET); extra=_Tracks[vidTrack].strf.size-sizeof(_video_bih); if(extra<0) { printf("[AVI]bih is not big enough (%"PRIu64"/%d)!\n",_Tracks[vidTrack].strf.size,(int)sizeof(_video_bih)); return 0; } fread(&_video_bih,sizeof(_video_bih),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_BitMapInfo(&_video_bih); #endif if(extra>0) { _videoExtraLen=extra; _videoExtraData=new uint8_t [extra]; fread(_videoExtraData,extra,1,_fd); } _isvideopresent=1; //-------------------------------------------------- // Read audio trak info, select if there is // several //-------------------------------------------------- // and audio track if(_mainaviheader.dwStreams>=2) { // which one is the audio track, is there several ? if(!(_nbAudioTracks=countAudioTrack())) { printf("Weird, there is no audio track, but more than one stream...\n"); } else { uint32_t run=0,audio=0; odmlAudioTrack *track; _audioTracks=new odmlAudioTrack[_nbAudioTracks]; _audioStreams=new ADM_audioStream *[_nbAudioTracks]; while(audio<_nbAudioTracks) { ADM_assert(run<_nbTrack); track=&(_audioTracks[audio]); fseeko(_fd,_Tracks[run].strh.offset,SEEK_SET); if(_Tracks[run].strh.size != sizeof(_audiostream)) { printf("[AVI]Mmm(2) we have a bogey here, size mismatch : %"PRIu64"\n",_Tracks[run].strh.size); printf("[AVI]expected %d\n",(int)sizeof(_audiostream)); if(_Tracks[run].strh.size<sizeof(_audiostream)-8) { GUI_Error_HIG(QT_TR_NOOP("Malformed header"), NULL); return 0; } printf("[AVI]Trying to continue anyway\n"); } fread(track->avistream,sizeof(_audiostream),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_AviStreamHeader(track->avistream); #endif if(track->avistream->fccType!=MKFCC('a','u','d','s')) { printf("Not an audio track!\n"); run++; continue; } // now read extra stuff fseeko(_fd,_Tracks[run].strf.offset,SEEK_SET); extra=_Tracks[run].strf.size-sizeof(WAVHeader); if(extra<0) { printf("[AVI]WavHeader is not big enough (%"PRIu64"/%d)!\n", _Tracks[run].strf.size,(int)sizeof(WAVHeader)); return 0; } fread(track->wavHeader,sizeof(WAVHeader),1,_fd); #ifdef ADM_BIG_ENDIAN Endian_WavHeader(track->wavHeader); #endif if(extra>2) { fgetc(_fd);fgetc(_fd); extra-=2; track->extraDataLen=extra; track->extraData=new uint8_t [extra]; fread(track->extraData,extra,1,_fd); } track->trackNum=run; audio++; run++; } } } // now look at the index stuff // there could be 3 cases: // 1- It is a openDML index, meta index + several smaller index // 2- It is a legacy index (type 1 , most common) // 3- It is a broken index or no index at all // // If it is a openDML index we will find a "indx" field in the Tracks // Else we will find it in _regularIndex Track // Since openDML often also have a regular index we will try open DML first uint8_t ret=0; Dump(); // take the size of riff header and actual file size uint64_t riffSize; fseeko(_fd,0,SEEK_END); _fileSize=ftello(_fd); fseeko(_fd,0,SEEK_SET); read32(); riffSize=(uint64_t )read32(); // 1st case, we have an avi < 4 Gb // potentially avi type 1 #if 0 if((_fileSize<4*1024*1024*1024LL)&& // if riff size is ~ fileSize try regular index (abs(riffSize-_fileSize)<1024*1024)) #endif #define HAS(x) if(x) printf(#x" : yes\n"); else printf(#x" : no\n"); // If there is no openDML index HAS( _regularIndex.offset); HAS( _Tracks[vidTrack].indx.offset); if(!ret && _regularIndex.offset &&!_Tracks[vidTrack].indx.offset) // try regular avi if a idx1 field is there (avi index) ret=indexRegular(vidTrack); if (!ret && _Tracks[vidTrack].indx.offset) // Try openDML if a index field is there (openDML) ret=indexODML(vidTrack); if(!ret) { printf("Could not index it properly...\n"); return 0; } if(!_nbAudioTracks) { _isaudiopresent=0; } else { odmlAudioTrack *track; // Check it is not a weird DV file if(fourCC::check(_video_bih.biCompression,(uint8_t *)"dvsd")) { for(int i=0;i<_nbAudioTracks;i++) { track=&(_audioTracks[i]); WAVHeader *hdr= track->wavHeader; if(!hdr->frequency) { ADM_warning("Fixing audio track to be PCM\n"); hdr->frequency=48000; //hdr->channels=2; hdr->byterate=48000*hdr->channels*2; hdr->blockalign=2*hdr->channels; } } } // build audio stream for(int i=0;i<_nbAudioTracks;i++) { track=&(_audioTracks[i]); ADM_aviAudioAccess *access=new ADM_aviAudioAccess(track->index,track->wavHeader, track->nbChunks, myName, track->extraDataLen,track->extraData); _audioStreams[i]= ADM_audioCreateStream((track->wavHeader), access); } } if(!_video_bih.biCompression && fourCC::check(_videostream.fccHandler,(uint8_t*)"DIB ")) { _videostream.fccHandler=_video_bih.biCompression=fourCC::get((uint8_t*)"DIB "); } else _videostream.fccHandler=_video_bih.biCompression; printf("\nOpenDML file successfully read..\n"); if(ret==1) { computePtsDts(); removeEmptyFrames(); } ADM_info("PtsAvailable : %d\n",(int)ptsAvailable); return ret; }
/** \fn A_openAvi \brief Open (replace mode) a video */ int A_openAvi (const char *name) { uint8_t res; char *longname; uint32_t magic[4]; uint32_t id = 0; if (playing) return 0; /// check if name exists FILE *fd; fd = ADM_fopen(name, "rb"); if (!fd) { if (errno == EACCES) { GUI_Error_HIG(QT_TRANSLATE_NOOP("adm", "Permission error"), QT_TRANSLATE_NOOP("adm", "Cannot open \"%s\"."), name); } if (errno == ENOENT) { GUI_Error_HIG(QT_TRANSLATE_NOOP("adm", "File error"), QT_TRANSLATE_NOOP("adm", "\"%s\" does not exist."), name); } return 0; } if (4 == fread(magic, 4, 4, fd)) id = R32(magic[0]); fclose(fd); GUI_close(); // Cleanup // DIA_StartBusy (); /* ** we may get a relative path by cmdline */ longname = ADM_PathCanonize(name); // check if avisynth input is given if (fourCC::check(id, (uint8_t *) "ADAP")) res = video_body->addFile(AVS_PROXY_DUMMY_FILE); else res = video_body->addFile(longname); // DIA_StopBusy (); // forget last project file video_body->setProjectName(""); if (res != ADM_OK) // an error occured { delete[] longname; if (ADM_IGN == res) { return 0; } if (fourCC::check(id, (uint8_t *) "//AD")) { GUI_Error_HIG(QT_TRANSLATE_NOOP("adm", "Cannot open project using the video loader."), QT_TRANSLATE_NOOP("adm", "Try 'File' -> 'Load/Run Project...'")); } else { GUI_Error_HIG(QT_TRANSLATE_NOOP("adm", "Could not open the file"), NULL); } return 0; } { int i; FILE *fd = NULL; char magic[4]; /* check myself it is a project file (transparent detected and read ** by video_body->addFile (name); */ //#warning FIXME #if 0 if ((fd = ADM_fopen(longname, "rb"))) { if (fread(magic, 4, 1, fd) == 4) { /* remember a workbench file */ if (!strncmp(magic, "ADMW", 4)) { actual_workbench_file = ADM_strdup(longname); } } fclose(fd); } #endif /* remember any video or workbench file to "recent" */ prefs->set_lastfile(longname); UI_updateRecentMenu(); updateLoaded(); if (currentaudiostream) { uint32_t nbAudio; audioInfo *infos = NULL; if (video_body->getAudioStreamsInfo(admPreview::getCurrentPts() + 1, &nbAudio, &infos)) { if (nbAudio > 1) { // Multiple track warn user GUI_Info_HIG(ADM_LOG_INFO, QT_TRANSLATE_NOOP("adm", "Multiple Audio Tracks"), QT_TRANSLATE_NOOP("adm", "The file you just loaded contains several audio tracks.\n" "Go to Audio->MainTrack to select the active one.")); } } if (infos) delete [] infos; // Revert mixer to copy //setCurrentMixerFromString("NONE"); EditableAudioTrack *ed = video_body->getDefaultEditableAudioTrack(); if (ed) ed->audioEncodingConfig.audioFilterSetMixer(CHANNEL_INVALID); } for (i = strlen(longname); i >= 0; i--) { #ifdef _WIN32 if (longname[i] == '\\' || longname[i] == '/') #else if (longname[i] == '/') #endif { i++; break; } } UI_setTitle(longname + i); } delete[] longname; return 1; }
//______________________________________ // // Open and recursively read the atoms // until we got the information we want // i.e. : // index for audio and video track // esds for mpeg4 // size / codec used // // We don't care about sync atom and all // other stuff which are pretty useless on // 3gp file anyway. //______________________________________ uint8_t MP4Header::open(const char *name) { printf("** opening 3gpp files **"); _fd=ADM_fopen(name,"rb"); if(!_fd) { printf("\n cannot open %s \n",name); return 0; } #define CLR(x) memset(& x,0,sizeof( x)); CLR( _videostream); CLR( _mainaviheader); _videostream.dwScale=1000; _videostream.dwRate=10000; _mainaviheader.dwMicroSecPerFrame=100000;; // 10 fps hard coded adm_atom *atom=new adm_atom(_fd); // Some mp4/mov files have the data at the end but do start properly // detect and workaround... // Check it is not mdat start(ADM_memcpy_0) uint8_t check[4]; uint64_t fileSize; fseeko(_fd,0,SEEK_END); fileSize=ftello(_fd); fseeko(_fd,4,SEEK_SET); fread(check,4,1,_fd); fseeko(_fd,0,SEEK_SET); if(check[0]=='m' && check[1]=='d' &&check[2]=='a' && check[3]=='t') { uint64_t of; uint64_t hi,lo; printf("Data first, header later...\n"); of=atom->read32(); if(of==1) { atom->read32(); // size atom->read32(); // fcc hi=atom->read32(); lo=atom->read32(); of=(hi<<32)+lo; if(of>fileSize) of=hi; } fseeko(_fd,of,SEEK_SET); printf("Header starts at %"PRIx64"\n",of); delete atom; atom=new adm_atom(_fd); } //************** if(!lookupMainAtoms((void*) atom)) { printf("Cannot find needed atom\n"); fclose(_fd); _fd=NULL; delete atom; return 0; } delete atom; _isvideopresent=1; _isaudiopresent=0; _videostream.fccType=fourCC::get((uint8_t *)"vids"); _video_bih.biBitCount=24; _videostream.dwInitialFrames= 0; _videostream.dwStart= 0; printf("\n"); if(!VDEO.index) { printf("No index!\n"); return 0; } // If it is mpeg4 and we have extra data // Decode vol header to get the real width/height // The mpeg4/3GP/Mov header is often misleading if(fourCC::check(_videostream.fccHandler,(uint8_t *)"DIVX")) { if(VDEO.extraDataSize) { uint32_t w,h,ti; if(extractMpeg4Info(VDEO.extraData,VDEO.extraDataSize,&w,&h,&ti)) { printf("MP4 Corrected size : %"PRIu32" x %"PRIu32"\n",w,h); _video_bih.biWidth=_mainaviheader.dwWidth=w ; _video_bih.biHeight=_mainaviheader.dwHeight=h; } }else { printf("No extradata to probe\n");} } else { /* Same story for H263 : Analyze 1st frame to get the real width/height */ if(fourCC::check(_videostream.fccHandler,(uint8_t *)"H263")) { uint32_t w,h,sz; uint8_t *bfer=NULL; sz=VDEO.index[0].size; if(sz) { bfer=new uint8_t[sz]; ADMCompressedImage img; img.data=bfer; if(getFrame(0,&img)) { if(extractH263Info(bfer,sz,&w,&h)) { printf("H263 Corrected size : %"PRIu32" x %"PRIu32"\n",w,h); _video_bih.biWidth=_mainaviheader.dwWidth=w ; _video_bih.biHeight=_mainaviheader.dwHeight=h; } else { printf("H263 COULD NOT EXTRACT SIZE, using : %"PRIu32" x %"PRIu32"\n", _video_bih.biWidth, _video_bih.biHeight); } } delete [] bfer; } } } /* * Veryfy DTS<=PTS */ int nb=(int)_tracks[0].nbIndex; uint64_t delta,maxDelta=0; for(int i=0;i<nb;i++) { uint64_t pts,dts; dts=VDEO.index[i].dts; pts=VDEO.index[i].pts; if(pts==ADM_COMPRESSED_NO_PTS || dts==ADM_COMPRESSED_NO_PTS) continue; if(dts>=pts) { uint64_t delta=(uint64_t)(dts-pts); if(delta>maxDelta) maxDelta=delta; } } if(maxDelta) { shiftTimeBy(maxDelta); _movieDuration+=(maxDelta+999)/1000; } /* Now build audio tracks */ if(nbAudioTrack) _isaudiopresent=1; // Still needed ? adjustElstDelay(); // for(int audio=0;audio<nbAudioTrack;audio++) { switch(_tracks[1+audio]._rdWav.encoding) { // Lookup if AAC is lying about # of channels case WAV_AAC: { if(_tracks[1+audio].extraDataSize==2) { // Channels uint32_t word=(_tracks[1+audio].extraData[0]<<8)+_tracks[1+audio].extraData[1]; uint32_t chan=(word>>3)&0xf; uint32_t fqIndex=(word>>7)&0xf; printf("0x%x word, Channel : %d, fqIndex=%d\n",word,chan,fqIndex); } } break; case WAV_AC3: // same for ac3 { // read First chunk MP4Index *dex=_tracks[1+audio].index; int size=dex[0].size; uint8_t *buffer=new uint8_t[size]; fseeko(_fd,dex[0].offset,SEEK_SET); if(fread(buffer,1,size,_fd)) { uint32_t fq, br, chan, syncoff; if(ADM_AC3GetInfo(buffer,size, &fq, &br, &chan,&syncoff)) { ADM_info("Updating AC3 info : Fq=%d, br=%d, chan=%d\n",fq,br,chan); _tracks[1+audio]._rdWav.channels=chan; _tracks[1+audio]._rdWav.byterate=br; } } delete [] buffer; } break; default: break; } audioAccess[audio]=new ADM_mp4AudioAccess(name,&(_tracks[1+audio])); audioStream[audio]=ADM_audioCreateStream(&(_tracks[1+audio]._rdWav), audioAccess[audio]); }
/** \fn saveAsJpg \brief save current image into filename, into jpg format */ bool ADMImage::saveAsJpg(const char *filename) { AVCodecContext *context=NULL; AVFrame frame; bool result=false; AVCodec *codec=NULL; int sz=0,r=0; ADM_byteBuffer byteBuffer; context=avcodec_alloc_context(); if(!context) { printf("[saveAsJpg] Cannot allocate context\n"); return false; } codec=avcodec_find_encoder(CODEC_ID_MJPEG); if(!codec) { printf("[saveAsJpg] Cannot allocate codec\n"); goto jpgCleanup; } context->pix_fmt =PIX_FMT_YUV420P; context->strict_std_compliance = -1; context->time_base.den=1; context->time_base.num=1; context->width=_width; context->height=_height; context->flags |= CODEC_FLAG_QSCALE; r=avcodec_open(context, codec); if(r<0) { printf("[saveAsJpg] Cannot mix codec and context\n"); ADM_dealloc (context); return false; } // Setup our image & stuff.... frame.linesize[0] = GetPitch(PLANAR_Y); frame.linesize[1] = GetPitch(PLANAR_U); frame.linesize[2] = GetPitch(PLANAR_V); frame.data[0] = GetWritePtr(PLANAR_Y); frame.data[2] = GetWritePtr(PLANAR_U); frame.data[1] = GetWritePtr(PLANAR_V); // Grab a temp buffer // Encode! frame.quality = (int) floor (FF_QP2LAMBDA * 2+ 0.5); byteBuffer.setSize(_width*_height*4); if ((sz = avcodec_encode_video (context, byteBuffer.at(0), _width*_height*4, &frame)) < 0) { printf("[jpeg] Error %d encoding video\n",sz); goto jpgCleanup; } // Ok now write our file... { FILE *f=ADM_fopen(filename,"wb"); if(f) { fwrite(byteBuffer.at(0),sz,1,f); fclose(f); result=true; }else { printf("[saveAsJpeg] Cannot open %s for writing!\n",filename); } } // Cleanup jpgCleanup: if(context) { avcodec_close (context); av_free (context); } context=NULL; return result; }
/** \fn saveAsBmp \brief save current image into filename, into bmp format */ bool ADMImage::saveAsBmp(const char *filename) { ADM_BITMAPFILEHEADER bmfh; ADM_BITMAPINFOHEADER bmph; FILE *fd; uint32_t sz; uint16_t s16; uint32_t s32; sz = _width* _height * 3; bmfh.bfReserved1 = bmfh.bfReserved2 = 0; bmfh.bfOffBits = sizeof (bmfh) + sizeof (bmph); //_________________________________________ bmph.biSize = sizeof (bmph); bmph.biWidth = _width; bmph.biHeight = _height; bmph.biPlanes = 1; bmph.biBitCount = 24; bmph.biCompression = 0; // COMPRESSION NONE bmph.biSizeImage = sz; bmph.biXPelsPerMeter = 0; bmph.biYPelsPerMeter = 0; bmph.biClrUsed = 0; bmph.biClrImportant = 0; /* bmph.resolutionUnits=0; bmph.origin=0; bmph.colorEncoding=0; */ ADMImageDefault image(_width,_height); printf ("\n %u x %u=%u\n", bmph.biWidth, bmph.biHeight, sz); uint8_t *out; out=(uint8_t *)ADM_alloc(sz); if(!out) { GUI_Error_HIG(QT_TR_NOOP("Memory error"), NULL); // ADM_dealloc(out); return 0; } ADMColorScalerSimple converter(bmph.biWidth, bmph.biHeight, ADM_COLOR_YV12,ADM_COLOR_RGB24); converter.convertImage(this,out); uint32_t ww=bmph.biWidth; uint32_t hh=bmph.biHeight; uint8_t *swap = new uint8_t[ww*3]; uint8_t *up=out; uint8_t *down=out+(hh-1)*ww*3; for(int y=0;y<hh>>1;y++) { SwapMe(swap,up,ww); SwapMe(up,down,ww); memcpy( down,swap,ww*3); down-=3*ww; up+=3*ww; } delete [] swap; fd = ADM_fopen (filename, "wb"); if (!fd) { GUI_Error_HIG (QT_TR_NOOP("Something bad happened"), NULL); ADM_dealloc(out); return 0; } // Bitmpap file header, not using tructure due to gcc padding it #ifdef ADM_BIG_ENDIAN s16 = 0x424D; #else s16 = 0x4D42; #endif s32 = 14 + sizeof (bmph) + sz; #ifdef ADM_BIG_ENDIAN #define SWAP32(x) x=R32(x) #else #define SWAP32(x) ; #endif SWAP32(s32); fwrite (&s16, 2, 1, fd); fwrite (&s32, 4, 1, fd); s32 = 0; fwrite (&s32, 4, 1, fd); s32 = 14 + sizeof (bmph); SWAP32(s32); fwrite (&s32, 4, 1, fd); #ifdef ADM_BIG_ENDIAN Endian_BitMapInfo(&bmph); #endif fwrite (&bmph, sizeof (bmph), 1, fd); fwrite (out, sz, 1, fd); fclose(fd); ADM_dealloc(out); return 1; }
/** \fn create_edAudioExternal */ ADM_edAudioTrackExternal *create_edAudioExternal(const char *name) { #define EXTERNAL_PROBE_SIZE (1024*1024) // Identify file type uint8_t buffer[EXTERNAL_PROBE_SIZE]; FILE *f=ADM_fopen(name,"rb"); if(!f) { ADM_warning("Cannot open %s\n",name); return NULL; } fread(buffer,1,EXTERNAL_PROBE_SIZE,f); fclose(f); WAVHeader hdr; uint32_t offset; if(false==ADM_identifyAudioStream(EXTERNAL_PROBE_SIZE,buffer,hdr,offset)) { ADM_warning("Cannot identify external audio track\n"); return NULL; } // Try to create an access for the file... ADM_audioAccess *access=NULL; switch(hdr.encoding) { case WAV_AAC: access=new ADM_audioAccessFileAACADTS(name,offset); break; case WAV_PCM: case WAV_AC3: case WAV_MP2: case WAV_MP3: ADM_info("Found external audio track, encoding =%d offset=%d\n",(int)hdr.encoding,(int)offset); // create access access=new ADM_audioAccessFile(name,offset); break; default: ADM_warning("Unsupported external audio tracks \n"); return NULL; break; } if(!access) { ADM_warning("Cannot initialize access for audio track"); return NULL; } // create ADM_edAudioTrack ADM_edAudioTrackExternal *external=new ADM_edAudioTrackExternal(name, &hdr,access); uint32_t extraDataLen=0; uint8_t *extraData=NULL; access->getExtraData(&extraDataLen,&extraData); ADM_info("Trying to create external audio track with %d bytes of extraData %d\n",extraDataLen); if(!external->create(extraDataLen,extraData)) { delete external; external=NULL; ADM_warning("Failed to create external track from %s\n",name); return NULL; } // done! return external; }
/** \fn addFile \brief Load or append a file. The file type is determined automatically and the ad-hoc video decoder is spawned @param name: filename @return 1 on success, 0 on failure */ bool ADM_Composer::addFile (const char *name) { uint8_t ret = 0; aviInfo info; uint32_t magic; _VIDEOS video; if(!strcmp(name, AVS_PROXY_DUMMY_FILE)) magic=0; else { FILE *f=ADM_fopen(name,"r"); uint8_t buffer[4]; if(!f) return 0; fread(buffer,4,1,f); fclose(f); magic=(buffer[3]<<24)+(buffer[2]<<16)+(buffer[1]<<8)+(buffer[0]); } // First find the demuxer.... video._aviheader=ADM_demuxerSpawn(magic,name); if(!video._aviheader) { char str[512+1]; snprintf(str,512,QT_TR_NOOP("Cannot find a demuxer for %s"), name); str[512] = '\0'; GUI_Error_HIG(str,NULL); return false; } ret = video._aviheader->open(name); // check opening was successful if (ret == 0) { char str[512+1]; snprintf(str,512,QT_TR_NOOP("Attempt to open %s failed!"), name); str[512] = '\0'; GUI_Error_HIG(str,NULL); video._aviheader=NULL; return false; } /* check for resolution */ if( _segments.getNbRefVideos()) { /* append operation */ aviInfo info0, infox; _segments.getRefVideo(0)->_aviheader->getVideoInfo (&info0); video._aviheader->getVideoInfo (&infox); if( info0.width != infox.width || info0.height != infox.height ) { char str[512+1]; str[0] = '\0'; if( info0.width != infox.width ) strcpy(str,"width"); if( info0.height != infox.height ) snprintf(str+strlen(str),512-strlen(str), "%sheight%sdifferent between first and this video stream", (strlen(str)?" and ":""), (strlen(str)?" are ":" is ") ); str[512] = '\0'; GUI_Error_HIG(str,QT_TR_NOOP("You cannot mix different video dimensions yet. Using the partial video filter later, will not work around this problem. The workaround is:\n1.) \"resize\" / \"add border\" / \"crop\" each stream to the same resolution\n2.) concatinate them together")); delete video._aviheader; return false; } } // else update info video._aviheader->getVideoInfo (&info); video._aviheader->setMyName (name); // Printf some info about extradata uint32_t l=0; uint8_t *d=NULL; video._aviheader->getExtraHeaderData(&l,&d); if(l && d) { printf("[Editor]The video codec has some extradata (%d bytes)\n",l); mixDump(d,l); printf("\n"); } // 1st if it is our first video we update postproc if(!_segments.getNbRefVideos()) { uint32_t type=0,value=0; #if 0 if(!prefs->get(DEFAULT_POSTPROC_TYPE,&type)) type=3; if(!prefs->get(DEFAULT_POSTPROC_VALUE,&value)) value=3; #endif if(_pp) delete _pp; _pp=new ADM_PP(info.width,info.height); _pp->postProcType=type; _pp->postProcStrength=value; _pp->forcedQuant=0; _pp->update(); if(_imageBuffer) { if(_imageBuffer->quant) delete [] _imageBuffer->quant; _imageBuffer->quant=NULL; delete _imageBuffer; _imageBuffer=NULL; } _imageBuffer=new ADMImageDefault(info.width,info.height); _imageBuffer->_qSize= ((info.width+15)>>4)*((info.height+15)>>4); _imageBuffer->quant=new uint8_t[_imageBuffer->_qSize]; memset(_imageBuffer->quant,0,_imageBuffer->_qSize); _imageBuffer->_qStride=(info.width+15)>>4; // We also clear the filter queue... ADM_info("Clearing video filters\n"); ADM_vf_clearFilters(); }