📄 encoder.c
字号:
if (fread(buf->y, sizeof(unsigned char), nPixels, inFile->y) != nPixels) return 0; if (fread(buf->u, sizeof(unsigned char), nPixels/4, inFile->u) != nPixels/4) return 0; if (fread(buf->v, sizeof(unsigned char), nPixels/4, inFile->v) != nPixels/4) return 0; return 1;}static void writeCroppedFrameComponent(FILE *outFile, unsigned char *frameBuf, int bufWidth, int leftOffset, int topOffset, int outWidth, int outHeight){ int i; for (i = topOffset; i < (topOffset + outHeight); i ++) { fwrite(frameBuf + i * bufWidth + leftOffset, sizeof(unsigned char), outWidth, outFile); }}/* * writeFrame: * * Parameters: * buf Frame buffer * seqParam Encoding parameters * outFile Destination file * * Function: * Writes frame to the file. * The frame cropping is applied. * * Returns: * - */static void writeFrame(avceYUVbuffer_s *buf, avceOpenParams_s *seqParam, videoFile_s *outFile, int frameIdx){ int nPixels; int width, height; width = seqParam->picWidth - seqParam->cropOffsets[0] - seqParam->cropOffsets[1]; height = seqParam->picHeight - seqParam->cropOffsets[2] - seqParam->cropOffsets[3]; nPixels = width * height; switch (outFile->format) { case SEPARATE_YUV_FILES: fseek(outFile->y, frameIdx * nPixels, SEEK_SET); fseek(outFile->u, frameIdx * nPixels/4, SEEK_SET); fseek(outFile->v, frameIdx * nPixels/4, SEEK_SET); break; case COMBINED_YUV_FILE: fseek(outFile->y, (frameIdx * nPixels * 3)/2, SEEK_SET); break; } // take care of the frame cropping writeCroppedFrameComponent(outFile->y, buf->y, seqParam->picWidth, seqParam->cropOffsets[0], seqParam->cropOffsets[2], width, height); writeCroppedFrameComponent(outFile->u, buf->u, seqParam->picWidth >> 1, seqParam->cropOffsets[0] >> 1, seqParam->cropOffsets[2] >> 1, width >> 1, height >> 1); writeCroppedFrameComponent(outFile->v, buf->v, seqParam->picWidth >> 1, seqParam->cropOffsets[0] >> 1, seqParam->cropOffsets[2] >> 1, width >> 1, height >> 1);}/** putBytesByteStream:** Parameters:* stream Bitsream file* data Data to be written* len Length of data** Function:* Write bytes to bitstream file* ** Returns:* -**/void putBytesByteStream(FILE *stream, void *data, int len){ fwrite(data, len, 1, stream);}/* * main: * * Parameters: * argc Number of parameters * argv Parameter strings * * Function: * Encoder main function * * Returns: * 0 ok * <> 0 error */int main(int argc, char **argv){ userParam_s param; /* Parameters from user */ avceOpenParams_s seqParam; /* Parameters passed to encoder */ avceEncoder_t *encoder; /* Encoder instance */ avceStatistics_s frmStat; videoFile_s origFile; videoFile_s recoFile; int recoFlag; FILE *stream; FILE *cumuFp; int srcPicNum, dstPicNum,numSkippedFrames=0; int intraFlag, idrFlag; int qp; avceYUVbuffer_s origBuf, prevOrigBuf; avceYUVbuffer_s recoBuf; void *nalBuf; int nalBufSize; int result; int targetFpsTimes1000; int pType; int nalRefIdc; int intraComing; /* * Old name: scenecutComing. The next frame will be intra coded. * Either a refreshed picture or a scene cut picture. */ int intraFrm; /* Old name: scenecutFrm. Current frame is intra coded. */ int sceneId; /* Newly defined var */ int scenecutComing; /* Newly defined var: Indicates the coming of a scene cut picture */ int nextScFrameidx; /* The skipped pic in the orig seq is counted by the idx */ int lastIdrFrm; /* The frame idx of the last IDR picture */ /* Parse command line arguments */ processCommands(argc, argv, ¶m, &seqParam); targetFpsTimes1000 = seqParam.origFpsTimes1000/(param.frmSkip + 1); /* Open video files */ recoFlag = openVideoFiles(¶m, &origFile, &recoFile, &stream); /* Initialize encoder constants common to all encoder instances */ avceLoad(); /* * Open (encoder) sequence */ seqParam.offsetForRefFrame = param.frmSkip + 1; seqParam.numFrms = param.numFrms; seqParam.intraFreq = param.intraFreq; seqParam.idrFreq = param.idrFreq; seqParam.numNonref = param.numNonref; encoder = avceOpen(&seqParam,&nalBuf,&nalBufSize); putBytesByteStream(stream, nalBuf, nalBufSize); if (encoder == NULL) { fprintf(stderr, "Could not open sequence\n"); exit(1); } /* Allocate memory for original frame data */ allocOrigFrame(&origBuf, seqParam.picWidth, seqParam.picHeight); if (param.fScenecut) { allocOrigFrame(& prevOrigBuf, seqParam.picWidth, seqParam.picHeight); } /* * Encode sequence, one frame at a time */ pType = 0; // the first frame is always handled as the scene cut nextScFrameidx = 0; dstPicNum = 0; intraComing = 1; sceneId = -1; scenecutComing = 1; lastIdrFrm = -1; while (dstPicNum < param.numFrms) { int i, groupLen; int ltrCandidate; if (intraComing) { intraComing = 0; intraFrm = 1; groupLen = 1; // process this frame only } else { intraFrm = 0; groupLen = param.numNonref + 1; // group can not include next IDR if (param.idrFreq > 0) { int nextIdr; nextIdr = ROUND_UP(dstPicNum, param.idrFreq); // if the next IDR refresh picture is too close to another IDR picture, // it will not be a refresh IDR picture if (param.minIdrDistance > 0 && lastIdrFrm >= 0) { int nextSc = nextScFrameidx / (param.frmSkip + 1); if (nextIdr - lastIdrFrm < param.minIdrDistance || nextSc - nextIdr < param.minIdrDistance) nextIdr = nextSc; } if (nextIdr >= param.numFrms) nextIdr = param.numFrms; if (dstPicNum + groupLen - 1 >= nextIdr) groupLen = nextIdr - dstPicNum; if (groupLen == 0) intraComing = 1; } // groupLen will be adjusted again if there is a scene cut if ((param.fScenecut) && (groupLen > 0)) { if ((dstPicNum != 0)) { int pType; // have a scene cut in the group? should be done backward // but we want to use this process to generate a scene cut file also pType = 0; for (nextScFrameidx = dstPicNum; nextScFrameidx < (dstPicNum + groupLen); nextScFrameidx ++) { srcPicNum = param.startFrm + nextScFrameidx * (param.frmSkip + 1); readFrame(& origBuf, seqParam.picWidth, seqParam.picHeight, & origFile, srcPicNum); param.Sumuv = param.Sumy = 0; pType = scdSceneCut(origBuf.y, origBuf.u, origBuf.v, prevOrigBuf.y, prevOrigBuf.u, prevOrigBuf.v, seqParam.picWidth, seqParam.picHeight, 4, & param.Sumy, & param.Sumuv); if (pType) break; } } // this is the last frame in the group srcPicNum = param.startFrm + (dstPicNum + groupLen - 1) * (param.frmSkip + 1); // does the next scene cut fall within the group if (srcPicNum >= nextScFrameidx * (param.frmSkip + 1)) { intraComing = 1; // the last frame whould be the one right before scene cut groupLen = (nextScFrameidx - 1 - param.startFrm)/(param.frmSkip + 1) - dstPicNum + 1; if (groupLen < 0) // scene cut happens between this frame and the last encoded frame groupLen = 0; } } } if (groupLen == 0) // leave it to the next iteration continue; // decide number of pp frames, for (i = 0; i < groupLen; i ++) { int srcPicIdx; intraFlag = 0; idrFlag = 0; if (i == 0) { intraFlag = idrFlag = (intraFrm) ? 1 : 0; // for intraFrm, groupLen == 1 srcPicIdx = dstPicNum + groupLen - 1; nalRefIdc = 1; // store the last idr picture idx if (idrFlag) lastIdrFrm = srcPicIdx; // create the scene info SEI message here if ( scenecutComing && param.fScenecutSei) { fprintf(stderr, "writing scene info sei (%d)\n", sceneId); avceEncodeSceneInfo(encoder, sceneId, &nalBuf, &nalBufSize); putBytesByteStream(stream, nalBuf, nalBufSize); } } else { srcPicIdx = dstPicNum + i - 1; nalRefIdc = 0; } // we many want to insert intra frame, not idr frame for testing if (param.intraFreq > 0) { if ((srcPicIdx % param.intraFreq) == 0 && (intraFlag == 0)) intraFlag = 1; } // if there is no reference frame, this frame is always intra if ((intraFlag == 0) && (seqParam.maxNumRefFrms == 0)) intraFlag = 1; srcPicNum = param.startFrm + srcPicIdx * (param.frmSkip + 1); if (! readFrame(& origBuf, seqParam.picWidth, seqParam.picHeight, & origFile, srcPicNum)) break; // use this frame as the previous frame in scene cut detection if (i == 0 && param.fScenecut) { int lumaSize; lumaSize = seqParam.picWidth * seqParam.picHeight; memcpy(prevOrigBuf.y, origBuf.y, lumaSize); memcpy(prevOrigBuf.u, origBuf.u, lumaSize/4); memcpy(prevOrigBuf.v, origBuf.v, lumaSize/4); } // decide the qp to use for the frame // qpIntra is not used if intra frame is after q2Start if ((dstPicNum + i) >= param.q2Start) qp = param.qpInter2; else qp = intraFlag ? param.qpIntra : param.qpInter; if (nalRefIdc == 0) qp = param.qpNonref; // will this frame used as long term reference frame // this is a reference picture, however this should still be stored if this is not to be outputted ltrCandidate = 0; if (param.ltrFreq > 0) { if (((srcPicIdx - param.ltrStart) % param.ltrFreq) == 0) ltrCandidate = 1; } // modify the frame number if (idrFlag && (param.ltrIdr)) ltrCandidate = 1; /* Encoder one frame */ result = avceEncodeOneFrame(encoder, &origBuf, &recoBuf, intraFlag, idrFlag, scenecutComing, nalRefIdc, ltrCandidate, srcPicNum - param.startFrm, qp, &nalBuf, &nalBufSize); if (result == AVCE_ERROR) { fprintf(stderr, "Error occured while encoding\n"); exit(1); } /* If frame was not skipped, bits are written to file */ if (result != AVCE_FRAME_SKIPPED) { avceGetFrmStat(encoder, &frmStat); // change output layout, easier to load it into excel to do data analysis if (param.fInfo) { if (srcPicNum == 0) { int bits; bits = avceGetBitsSPS(encoder) + avceGetBitsPPS(encoder) + 10*8; printf(" %d\t %d\t %d \n", srcPicNum, (bits + frmStat.bits)/8, intraFlag); } else printf(" %d\t %d\t %d \n", srcPicNum, frmStat.bits/8, intraFlag); } else { { if(intraFlag ||idrFlag) printf("%3d(%s)\tbits\t%6d\tPsnrYUV\t%5.2f\t%5.2f\t%5.2f\tintraMb\t%d\t%5d %1d\n", srcPicNum, "I", frmStat.bits, frmStat.psnrY, frmStat.psnrU, frmStat.psnrV, frmStat.numIntraMbs, frmStat.bufFullness, intraFlag); else if(nalRefIdc == 1) printf("%3d(%s)\tbits\t%6d\tPsnrYUV\t%5.2f\t%5.2f\t%5.2f\tintraMb\t%d\t%5d %1d\n", srcPicNum, "P", frmStat.bits, frmStat.psnrY, frmStat.psnrU, frmStat.psnrV, frmStat.numIntraMbs, frmStat.bufFullness, intraFlag); else if(nalRefIdc == 0) printf("%3d(%s)\tbits\t%6d\tPsnrYUV\t%5.2f\t%5.2f\t%5.2f\tintraMb\t%d\t%5d %1d\n", srcPicNum, "p", frmStat.bits, frmStat.psnrY, frmStat.psnrU, frmStat.psnrV, frmStat.numIntraMbs, frmStat.bufFullness, intraFlag); } } putBytesByteStream(stream, nalBuf, nalBufSize); if (recoFlag) { writeFrame(& recoBuf, & seqParam, & recoFile, (srcPicNum - (numSkippedFrames*(param.frmSkip + 1)) - param.startFrm)/(param.frmSkip + 1)); } } else { if(intraFlag == 1) intraComing = 1; numSkippedFrames++; } } dstPicNum += groupLen; intraFrm = 0; scenecutComing = 0; } fprintf(stderr," took %5.3f seconds \n", (double)clock()/CLOCKS_PER_SEC); /* Append short sequence statistics to -cumul file if file present */ if (strlen(param.cumuFileName) != 0) { if ((cumuFp = fopen(param.cumuFileName, "a")) != NULL) { printSeqStat(encoder, param.qpIntra, param.qpInter, targetFpsTimes1000, numSkippedFrames, cumuFp); fclose(cumuFp); } } /* Print a bit more detailed statistics */ if(!param.fInfo) dumpStatistics(encoder, targetFpsTimes1000, numSkippedFrames); /* Close sequence */ avceClose(encoder); /* Free memory of original frame data */ freeOrigFrame(&origBuf); if (param.fScenecut) freeOrigFrame(&prevOrigBuf); /* Close video files */ closeFiles(&origFile, &recoFile, recoFlag, stream); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -