📄 tmp4.cpp
字号:
SKL_UINT32 Code = 0xDeadBeef; do Code = (Code<<8) | fgetc(f); while( Code!=Marker && !feof(f) ); return feof(f);}static long Parse_Input_File(SKL_BYTE *Buf, size_t Size, FILE *f){ int Ok = 0; if (System_Stream==1) // Ultra-Simplistic AVI Parser { static SKL_UINT32 Chunk_Size = 0; static int Have_MOVI = 0; if (!Have_MOVI) { const SKL_UINT32 _movi_ = FourCC( "movi" ); if (Locate_Marker(_movi_, f)) return 0; Have_MOVI = 1; } while(Size>0) { while (Chunk_Size==0) { SKL_UINT16 Nb = Get16b_LE(f); SKL_UINT32 Id = Get16b_LE(f); SKL_UINT32 S = Get32b_LE(f); S += (S&1); Nb = ((Nb>>8)-'0') + ((Nb&0xff)-'0')*10; if ( Nb!=0 || Id!=TwoCC( "dc" ) ) fseek(f, S, SEEK_CUR); else Chunk_Size = S; } size_t Gotten = fread(Buf+Ok, 1, (Size>Chunk_Size) ? Chunk_Size : Size, f); Ok += Gotten; Chunk_Size -= Gotten; Size -= Gotten; } } else if (System_Stream==1) // Ultra-Dumb MPG Parser { // not yet done... } else { Ok = fread(Buf, 1, Size, f); } return Ok;}////////////////////////////////////////////////////////////// main decoding loop (very decorated!)////////////////////////////////////////////////////////////static int Decode_MPEG4(SKL_CST_STRING Name){ // create codec instance MP4_New_Decoder = (SKL_MP4_NEW_DEC)SKL_LOAD_DYN_SYMBOL(SKL_MP4_DLL, Skl_MP4_New_Decoder); MP4_Delete_Decoder = (SKL_MP4_DELETE_DEC)SKL_LOAD_DYN_SYMBOL(SKL_MP4_DLL, Skl_MP4_Delete_Decoder); if (MP4_New_Decoder==0 || MP4_Delete_Decoder==0) // problem with DLL return -1; SKL_MP4_DEC *Dec = MP4_New_Decoder(); if (Dec==0) return -2; if (Trace_Mem) Dec->Set_Memory_Manager(All_Mem); Dec->Set_CPU( Cpu ); if (With_Slices) Dec->Set_Slicer(Display_Slice,0); // Dec debug level: 1:show MVs 2:print scanlines 3-4: print infos if (Debug>=4) Dec->Set_Debug_Level(Debug-3); // Prepare a PSNR_INFOS for external PSNR comparison PSNR_INFOS PSNR_Infos; // open I/O files FILE *f; long Fullness, Left_To_Read, Size, Left; SKL_BYTE *Buf, *mBuf = 0; const int MAX_BUF = 400000; // TODO: BAD SKL_BYTE Buf0[MAX_BUF+4] = {0}; // +4 = sentinel (just in case) int Err = 0; SKL_PTIMER pTimer; f = fopen( Name, "rb" ); if (f==0) { fprintf( stderr, "Can't open file '%s' for reading.\n", Name ); return -1; } fseek(f, 0, SEEK_END); Size = ftell(f); rewind(f); if (From_Mem) { mBuf = (SKL_BYTE*)All_Mem->New(Size); Buf = mBuf; Fullness = Parse_Input_File(Buf, Size, f); if (Fullness==0) { Err = -1; goto End; } Left_To_Read = 0; } else { Buf = Buf0; Left_To_Read = Size; Fullness = 0; if (Streaming && Jump_To>0) { if (!Quiet) printf( "Jumping to offset %ld in file\n", Jump_To ); fseek(f, Jump_To, SEEK_SET); // wowowow!! } } // main decoding loop if (!Quiet) printf( "Decoding MP4 bitstream '%s' (size:%ld).\n", Name, Size); Left = Size; pTimer.Reset(); while(Left>=0) { float Next_Tick = pTimer.Get_mSec(); if (!From_Mem && Fullness<MAX_BUF/2) { if (Fullness>0) memmove( Buf0, Buf, Fullness); Buf = Buf0; const int Free = MAX_BUF-Fullness; size_t More = (Left_To_Read>Free) ? Free : Left_To_Read; if (More>0) { More = Parse_Input_File(Buf+Fullness, More, f); Fullness += More; Left_To_Read -= More; } } int Read = MPEG12 ? Dec->Decode_MPEG12(Buf, Fullness) : Dec->Decode(Buf, Fullness); if (Read>Fullness) throw SKL_EXCEPTION( "Aieeee! Buffer read overflow" ); if (Debug==2) printf( " Left:%ld consumed:%d fullness=%ld\n", Left, Read, Fullness ); else if (Debug==3) // for gnuplot printf( "%d %d %ld\n", Dec->Get_Frame_Number(), Read, Fullness ); if (Left==0 && Read==0) Left = -1; // very last frame else Left -= Read; Buf += Read; Fullness -= Read; if (!Dec->Is_Frame_Ready() || Skip_Frames-->0) continue; if (Delay>0) pTimer.Wait(1.0f*Delay); else if (FPS>0.) { Next_Tick += 1000.f / FPS - pTimer.Get_mSec(); if (Next_Tick>0.) pTimer.Wait(Next_Tick); /* else: Hurry up! */ } pTimer++; SKL_MP4_PIC Pic; if (VTrace==4) Dec->Get_All_Frames(&Pic); else { Dec->Consume_Frame(&Pic); if (Debug==1) printf( "Decoded frame #%d (Time stamp=%.3f s) \r", Dec->Get_Frame_Number(), Pic.Time); if (Show_PSNR) Compare_PSNR_External(&Pic, &PSNR_Infos); } Deal_With_Pic( Pic, Dec->Get_Frame_Number() ); if (!Quiet && pTimer.Get_Count()==1) printf( " - Frames size: %dx%d\n", Pic.Width, Pic.Height ); if (!Streaming && Jump_To>0 && !From_Mem && pTimer.Get_Count()==1) { if (!Quiet) printf( "Jumping to offset %ld in file\n", Jump_To ); fseek(f, Jump_To, SEEK_SET); // wowowow!! Fullness = 0; } if (!--Nb_Frames) break; } if (Quiet!=1) pTimer.Elapsed_FPS(0,"\n");End: if (f!=0) fclose(f); if (From_Mem) All_Mem->Delete(mBuf, Size); MP4_Delete_Decoder(Dec); return Err;}////////////////////////////////////////////////////////////// Encoding////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// example of external "Slicer" hook // => computes PSNR for each slice////////////////////////////////////////////////////////////static void Sliced_PSNR(const SKL_MP4_PIC *Pic, int yo, int Height, SKL_ANY Data){ PSNR_INFOS *I = (PSNR_INFOS*)Data; if (Height==0) // start/end of scan? { if (yo==0) { // start of scan I->Check(Pic->Width, Pic->Height, Pic->BpS); I->Store(I->Y, Pic->Y, Pic->Width, Pic->Height, Pic->BpS); I->Store(I->U, Pic->U, Pic->Width/2, Pic->Height/2, Pic->BpS); I->Store(I->V, Pic->V, Pic->Width/2, Pic->Height/2, Pic->BpS); } else { // end of scan SKL_UINT32 SSE_Y = I->Get_SSE(I->Y, Pic->Y, Pic->Width, Pic->Height, Pic->BpS); SKL_UINT32 SSE_U = I->Get_SSE(I->U, Pic->U, Pic->Width/2, Pic->Height/2, Pic->BpS); SKL_UINT32 SSE_V = I->Get_SSE(I->V, Pic->V, Pic->Width/2, Pic->Height/2, Pic->BpS); Img_Dsp.Switch_Off(); I->PSNR_Y += I->pY = I->Compute_PSNR(SSE_Y, Pic->Width*Pic->Height); I->PSNR_U += I->pU = I->Compute_PSNR(SSE_U, Pic->Width*Pic->Height/4); I->PSNR_V += I->pV = I->Compute_PSNR(SSE_V, Pic->Width*Pic->Height/4); I->PSNR_A += I->pA = I->Compute_PSNR(SSE_Y+SSE_U+SSE_V, 3*Pic->Width*Pic->Height/2); I->Cnt++; if (I->Cnt==10000) { // reset every ~10000 frames, to avoid overflow... // (yeah, I know, we won't end up with the real PSNR :) I->PSNR_Y /= I->Cnt; I->PSNR_U /= I->Cnt; I->PSNR_V /= I->Cnt; I->PSNR_A /= I->Cnt; I->Cnt = 1; } } } else { /* we're in a slice. */ }}////////////////////////////////////////////////////////////// Main encoding loop////////////////////////////////////////////////////////////static int Parse_Custom_Matrix_File(SKL_MP4_ENC *const Enc){ FILE *f = fopen(Custom_Matrix, "r"); if (f==0) { fprintf( stderr, "Can't open custom matrix file [%s]\n", Custom_Matrix ); return 0; } SKL_BYTE M[2*64]; int i, k; for(i=0; i<2*64; ++i) if (fscanf(f, "%d", &k)!=1) return 0; else M[i] = k; fclose(f); Enc->Set_Custom_Matrix(0, M+ 0); Enc->Set_Custom_Matrix(1, M+64); return 1;}static int Encode_MPEG4(SKL_CST_STRING Out_Name, SKL_CST_STRING In_Name){ // create an encoder instance MP4_New_Encoder = (SKL_MP4_NEW_ENC)SKL_LOAD_DYN_SYMBOL(SKL_MP4_DLL, Skl_MP4_New_Encoder); MP4_Delete_Encoder = (SKL_MP4_DELETE_ENC)SKL_LOAD_DYN_SYMBOL(SKL_MP4_DLL, Skl_MP4_Delete_Encoder); if (MP4_New_Encoder==0 || MP4_Delete_Encoder==0) // problem with DLL return -1; SKL_MP4_ENC *Enc = MP4_New_Encoder(); if (Enc==0) return -2; /* Enc debug level: 1:show MVs 2:print scanlines 3-4: print infos */ if (Debug>=4) Enc->Set_Debug_Level(Debug-3); Enc->Set_CPU( Cpu ); Enc->Set_Memory_Manager(All_Mem); Enc->Get_Analyzer()->Set_Memory_Manager(All_Mem); if (Streaming) Enc->Ioctl( "emit-key-headers" ); if (Sequence_Codes) Enc->Ioctl( "emit-sequence-codes" ); if (Custom_Matrix) if (!Parse_Custom_Matrix_File(Enc)) { fprintf( stderr, "Custom matrix parsing failed!\n" ); return -2; } // warm up the analyzer if (FPS==0) FPS = 29.970f; // dflt value Enc->Get_Analyzer()->Set_Param( "bitrate", Bit_Rate ); Enc->Get_Analyzer()->Set_Param( "framerate", FPS ); Enc->Get_Analyzer()->Set_Param( "base-quant", Global_Q ); Enc->Get_Analyzer()->Set_Param( "quant", Global_Q ); Enc->Get_Analyzer()->Set_Param( "quant-type", Quant_Type ); Enc->Get_Analyzer()->Set_Param( "intra-max-delay", Intra_Max ); Enc->Get_Analyzer()->Set_Param( "4v-probing", Inter4V_Probing ); Enc->Get_Analyzer()->Set_Param( "field-pred-probing", Field_Pred_Probing ); Enc->Get_Analyzer()->Set_Param( "gmc-mode", Use_GMC ); Enc->Get_Analyzer()->Set_Param( "gmc-pts", 3 ); Enc->Get_Analyzer()->Set_Param( "gmc-accuracy", GMC_Accuracy ); Enc->Get_Analyzer()->Set_Param( "reduced-frame", Use_Reduced ); Enc->Get_Analyzer()->Set_Param( "interlace-field", Interlace_Field ); Enc->Get_Analyzer()->Set_Param( "rounding", 0 ); Enc->Get_Analyzer()->Set_Param( "search-metric", Search_Metric ); Enc->Get_Analyzer()->Set_Param( "sad-skip-limit", SAD_Skip_Limit ); Enc->Get_Analyzer()->Set_Param( "sad-intra-limit", SAD_Intra_Limit ); Enc->Get_Analyzer()->Set_Param( "interlace-dct", Interlace_DCT ); Enc->Get_Analyzer()->Set_Param( "base-search-size", MV_Size ); Enc->Get_Analyzer()->Set_Param( "search-size", MV_Size ); Enc->Get_Analyzer()->Set_Param( "search-method", Search_Method ); Enc->Get_Analyzer()->Set_Param( "subpixel", Sub_Pixel ); Enc->Get_Analyzer()->Set_Param( "dquant-amp", dQuant_Amp ); Enc->Get_Analyzer()->Set_Param( "lambda", Lambda ); Enc->Get_Analyzer()->Set_Param( "intra-limit", Intra_Limit ); Enc->Get_Analyzer()->Set_Param( "inter-threshold", Inter_Thresh ); Enc->Get_Analyzer()->Set_Param( "use-trellis", Use_Trellis ); Enc->Get_Analyzer()->Set_Param( "hi-mem", Hi_Mem ); Enc->Get_Analyzer()->Set_Param( "buffer-size", Enc_Buf_Size ); Enc->Get_Analyzer()->Set_Param( "verbose", ADebug ); Enc->Get_Analyzer()->Set_Param( "pass", Pass_Nb); Enc->Get_Analyzer()->Set_Param( "passfile", Pass_File); Enc->Get_Analyzer()->Set_Param( "passrf", Pass_RF); // plug PNSR slicer hook PSNR_INFOS PSNR_Infos; if (Show_PSNR&(1|2)) Enc->Set_Slicer(Sliced_PSNR, (SKL_ANY)&PSNR_Infos); // open I/O files int Err = 0; FILE *In = 0, *Out = 0; int Cnt = 0; int W=0, H=0; int Pos = 0; SKL_PTIMER pTimer; long Out_Size = 0; if (In_Name) { In = fopen(In_Name, "rb"); if (In==0) { fprintf( stderr, "Can't open file '%s'!\n", In_Name ); Err = -1; goto End; } } else In = stdin; if (Out_Name!=0) { Out = fopen(Out_Name, "wb"); if (Out==0) { fprintf( stderr, "Can't open file '%s' for writing.", Out_Name ); Err = -1; goto End; } if (!Quiet) printf( "Encoding MP4 bitstream '%s'.\n", Out_Name); } else SKL_ASSERT(Pass_Nb==1); // Pass #1 doesn't require to output a bitstream (just stats) // main loop pTimer.Reset(); while( PGM_In(Enc, In, &W, &H, Cnt*1000./FPS) ) { if (Skip_Frames-->0) continue; if (Use_Reduced>=0 && (((W/16)&1) || ((H*2/3/16)&1)) ) { printf( "Reduced frames problem: Frame size %dx%d cannot be split into 32x32 blocks!!\n", W, H ); goto End; } ++Cnt; if (!Quiet) if (!(Cnt&0xf)) printf( "Encoding frame #%d \r", Cnt ); Enc->Encode(); if (Enc->Get_Bits_Length()) { if (Out!=0 && fwrite( Enc->Get_Bits(), Enc->Get_Bits_Length(), 1, Out )!=1) { fprintf( stderr, "Write error!\n" ); Err = -1; goto End; } Out_Size += Enc->Get_Bits_Length();// Example of key-frame detection:// const SKL_MP4_PIC *Last = Enc->Get_Last_Coded_Frame();// if (Last->Coding==0) printf( "Key frame! (%ld) ", Last->Time_Ticks ); if (Debug==2) { printf( " Pos:%d Frame size:%d\n", Pos, Enc->Get_Bits_Length()); Pos += Enc->Get_Bits_Length(); } } pTimer++; if (Show_PSNR&1) PSNR_Infos.Print_Infos(); if (VTrace!=0) { SKL_MP4_PIC Pic; Enc->Get_All_Frames(&Pic); Deal_With_Pic(Pic, pTimer.Get_Count()); } if (!--Nb_Frames) break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -