📄 avi.cpp
字号:
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is MPEG4IP. * * The Initial Developer of the Original Code is Cisco Systems Inc. * Portions created by Cisco Systems Inc. are * Copyright (C) Cisco Systems Inc. 2000-2002. All Rights Reserved. * * Contributor(s): * Dave Mackie dmackie@cisco.com *//* * Notes: * - file formatted with tabstops == 4 spaces */#include <mp4creator.h>#include <avilib.h>static MP4TrackId VideoCreator(MP4FileHandle mp4File, avi_t* aviFile){ char* videoType = AVI_video_compressor(aviFile); u_int8_t videoProfileLevel = 0x03; if (strcasecmp(videoType, "divx") && strcasecmp(videoType, "dx50") && strcasecmp(videoType, "xvid")) { fprintf(stderr, "%s: video compressor %s not recognized\n", ProgName, videoType); return MP4_INVALID_TRACK_ID; } double frameRate = AVI_video_frame_rate(aviFile); if (frameRate == 0) { fprintf(stderr, "%s: no video frame rate in avi file\n", ProgName); return MP4_INVALID_TRACK_ID; }#ifdef _WIN32 MP4Duration mp4FrameDuration; mp4FrameDuration = (MP4Duration)((double)Mp4TimeScale / frameRate);#else MP4Duration mp4FrameDuration = (MP4Duration)(Mp4TimeScale / frameRate);#endif MP4TrackId trackId = MP4AddVideoTrack( mp4File, Mp4TimeScale, mp4FrameDuration, AVI_video_width(aviFile), AVI_video_height(aviFile), MP4_MPEG4_VIDEO_TYPE); if (trackId == MP4_INVALID_TRACK_ID) { fprintf(stderr, "%s: can't create video track\n", ProgName); return MP4_INVALID_TRACK_ID; } int32_t i; int32_t numFrames = AVI_video_frames(aviFile); int32_t frameSize; int32_t maxFrameSize = 0; // determine maximum video frame size AVI_seek_start(aviFile); for (i = 0; i < numFrames; i++) { frameSize = AVI_frame_size(aviFile, i); if (frameSize > maxFrameSize) { maxFrameSize = frameSize; } } // allocate a large enough frame buffer u_int8_t* pFrameBuffer = (u_int8_t*)malloc(maxFrameSize + 4); if (pFrameBuffer == NULL) { fprintf(stderr, "%s: can't allocate memory\n", ProgName); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } AVI_seek_start(aviFile); // read first frame, should contain VO/VOL and I-VOP frameSize = AVI_read_frame(aviFile, (char*)pFrameBuffer); if (frameSize < 0) { fprintf(stderr, "%s: can't read video frame 1: %s\n", ProgName, AVI_strerror()); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } // find VOP start code in first sample static u_int8_t startCode[3] = { 0x00, 0x00, 0x01, }; u_int32_t vopStart = 0; bool foundVOP = false; bool foundVOSH = false; bool foundVisualObjectStart = false; bool foundVO = false; bool foundVOL = false; // Note that we go from 4 to framesize, not 0 to framesize - 4 // this is adding padding at the beginning for the VOSH, if // needed for (i = 0; foundVOP == false && i < frameSize; i++) { if (!memcmp(&pFrameBuffer[i], startCode, 3)) { // everything before the VOP // should be configuration info if (pFrameBuffer[i + 3] == MP4AV_MPEG4_VOP_START) { vopStart = i; foundVOP = true; } else if (pFrameBuffer[i + 3] == MP4AV_MPEG4_VOL_START) { u_int8_t timeBits = 15; u_int16_t timeTicks = 30000; u_int16_t frameDuration = 3000; u_int16_t frameWidth = 0; u_int16_t frameHeight = 0; if (MP4AV_Mpeg4ParseVol(pFrameBuffer + i, frameSize - i, &timeBits, &timeTicks, &frameDuration, &frameWidth, &frameHeight) == false) { fprintf(stderr, "Couldn't parse vol\n"); } if (frameWidth != AVI_video_width(aviFile)) { fprintf(stderr, "%s:avi file video width does not match VOL header - %d vs. %d\n", ProgName, frameWidth, AVI_video_width(aviFile)); } if (frameHeight != AVI_video_height(aviFile)) { fprintf(stderr, "%s:avi file video height does not match VOL header - %d vs. %d\n", ProgName, frameHeight, AVI_video_height(aviFile)); } foundVOL = true; } else if (pFrameBuffer[i + 3] == MP4AV_MPEG4_VOSH_START) { foundVOSH = true; MP4AV_Mpeg4ParseVosh(pFrameBuffer + i, frameSize - i, &videoProfileLevel); } else if (pFrameBuffer[i + 3] == MP4AV_MPEG4_VO_START) { foundVisualObjectStart = true; } else if (pFrameBuffer[i + 3] <= 0x1f) { foundVO = true; } i += 3; // skip past header } } if (foundVOSH == false) { fprintf(stderr, "%s: Warning: no Visual Object Sequence Start (VOSH) header found in MPEG-4 video.\n" "This can cause problems with players other than mp4player included\n" "with this package.\n", ProgName); } else { if (VideoProfileLevelSpecified && videoProfileLevel != VideoProfileLevel) { fprintf(stderr, "%s: You have specified a different video profile level than was detected in the VOSH header\n" "The level you specified was %d and %d was read from the VOSH\n", ProgName, VideoProfileLevel, videoProfileLevel); } } if (foundVisualObjectStart == false) { fprintf(stderr, "%s: Warning: no Visual Object start header found in MPEG-4 video.\n" "This can cause problems with players other than mp4player included\n" "with this package.\n", ProgName); } if (foundVO == false) { fprintf(stderr, "%s: Warning: No VO header found in mpeg-4 video.\n" "This can cause problems with players other than mp4player\n", ProgName); } if (foundVOL == false) { fprintf(stderr, "%s: fatal: No VOL header found in mpeg-4 video stream\n", ProgName); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; }#if 0 // the below will write a VOSH and VO if one doesn't exist if (foundVOSH == false || foundVisualObjectStart == false) { uint8_t *tempes = (uint8_t *)malloc(vopStart + 1 + 5 + 9); uint32_t templen = 0; if (foundVOSH == false) { MP4AV_Mpeg4CreateVosh(&tempes,&templen, videoProfileLevel); } if (foundVisualObjectStart == false) { MP4AV_Mpeg4CreateVo(&tempes, &templen, 1); } memcpy(tempes + templen, pFrameBuffer, vopStart + 1); MP4SetTrackESConfiguration(mp4File, trackId, tempes, vopStart + 1 + templen); free(tempes); } else { MP4SetTrackESConfiguration(mp4File, trackId, pFrameBuffer, vopStart + 1); }#else MP4SetTrackESConfiguration(mp4File, trackId, pFrameBuffer, vopStart + 1);#endif if (MP4GetNumberOfTracks(mp4File, MP4_VIDEO_TRACK_TYPE) == 1) { if (VideoProfileLevelSpecified) { videoProfileLevel = VideoProfileLevel; } MP4SetVideoProfileLevel(mp4File, MP4AV_Mpeg4VideoToSystemsProfileLevel(videoProfileLevel)); } // write out the first frame, minus the initial configuration info MP4WriteSample( mp4File, trackId, &pFrameBuffer[vopStart], frameSize - vopStart, mp4FrameDuration, 0, true); // process the rest of the frames for (i = 1; i < numFrames; i++) { // read the frame from the AVI file frameSize = AVI_read_frame(aviFile, (char*)pFrameBuffer); if (frameSize < 0) { fprintf(stderr, "%s: can't read video frame %i: %s\n", ProgName, i + 1, AVI_strerror()); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } // we mark random access points in MP4 files bool isIFrame = (MP4AV_Mpeg4GetVopType(pFrameBuffer, frameSize) == 'I'); // write the frame to the MP4 file MP4WriteSample(mp4File, trackId, pFrameBuffer, frameSize, mp4FrameDuration, 0, isIFrame); } return trackId;}static inline u_int32_t BytesToInt32(u_int8_t* pBytes) { return (pBytes[0] << 24) | (pBytes[1] << 16) | (pBytes[2] << 8) | pBytes[3];}static MP4TrackId AudioCreator(MP4FileHandle mp4File, avi_t* aviFile){ int32_t audioType = AVI_audio_format(aviFile); // Check for MP3 audio type if (audioType != 0x55) { fprintf(stderr, "%s: audio compressor 0x%x not recognized\n", ProgName, audioType); return MP4_INVALID_TRACK_ID; } u_int8_t temp[4]; u_int32_t mp3header; AVI_seek_start(aviFile); if (AVI_read_audio(aviFile, (char*)&temp, 4) != 4) { fprintf(stderr, "%s: can't read audio frame 0: %s\n", ProgName, AVI_strerror()); return MP4_INVALID_TRACK_ID; } mp3header = BytesToInt32(temp); // check mp3header sanity if ((mp3header & 0xFFE00000) != 0xFFE00000) { fprintf(stderr, "%s: data in file doesn't appear to be valid mp3 audio\n", ProgName); return MP4_INVALID_TRACK_ID; } u_int16_t samplesPerSecond = MP4AV_Mp3GetHdrSamplingRate(mp3header); u_int16_t samplesPerFrame = MP4AV_Mp3GetHdrSamplingWindow(mp3header); u_int8_t mp4AudioType = MP4AV_Mp3ToMp4AudioType(MP4AV_Mp3GetHdrVersion(mp3header)); if (audioType == MP4_INVALID_AUDIO_TYPE || samplesPerSecond == 0) { fprintf(stderr, "%s: data in file doesn't appear to be valid mp3 audio\n", ProgName); return MP4_INVALID_TRACK_ID; } MP4TrackId trackId = MP4AddAudioTrack(mp4File, samplesPerSecond, samplesPerFrame, mp4AudioType); if (trackId == MP4_INVALID_TRACK_ID) { fprintf(stderr, "%s: can't create audio track\n", ProgName); return MP4_INVALID_TRACK_ID; } if (MP4GetNumberOfTracks(mp4File, MP4_AUDIO_TRACK_TYPE) == 1) { MP4SetAudioProfileLevel(mp4File, 0xFE); } int32_t i; int32_t aviFrameSize; int32_t maxAviFrameSize = 0; // determine maximum avi audio chunk size // should be at least as large as maximum mp3 frame size AVI_seek_start(aviFile); i = 0; while (AVI_set_audio_frame(aviFile, i, (long*)&aviFrameSize) == 0) { if (aviFrameSize > maxAviFrameSize) { maxAviFrameSize = aviFrameSize; } i++; } // allocate a large enough frame buffer u_int8_t* pFrameBuffer = (u_int8_t*)malloc(maxAviFrameSize); if (pFrameBuffer == NULL) { fprintf(stderr, "%s: can't allocate memory\n", ProgName); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } AVI_seek_start(aviFile); u_int32_t mp3FrameNumber = 1; while (true) { if (AVI_read_audio(aviFile, (char*)pFrameBuffer, 4) != 4) { // EOF presumably break; } mp3header = BytesToInt32(&pFrameBuffer[0]); u_int16_t mp3FrameSize = MP4AV_Mp3GetFrameSize(mp3header); int bytesRead = AVI_read_audio(aviFile, (char*)&pFrameBuffer[4], mp3FrameSize - 4); if (bytesRead != mp3FrameSize - 4) { fprintf(stderr, "%s: Warning, incomplete audio frame %u, ending audio track\n", ProgName, mp3FrameNumber); break; } if (!MP4WriteSample(mp4File, trackId, &pFrameBuffer[0], mp3FrameSize)) { fprintf(stderr, "%s: can't write audio frame %u\n", ProgName, mp3FrameNumber); MP4DeleteTrack(mp4File, trackId); return MP4_INVALID_TRACK_ID; } mp3FrameNumber++; } return trackId;}MP4TrackId* AviCreator(MP4FileHandle mp4File, const char* aviFileName){ static MP4TrackId trackIds[3]; u_int8_t numTracks = 0; avi_t* aviFile = AVI_open_input_file(aviFileName, true); if (aviFile == NULL) { fprintf(stderr, "%s: can't open %s: %s\n", ProgName, aviFileName, AVI_strerror()); } else { if (AVI_video_frames(aviFile) > 0) { trackIds[numTracks] = VideoCreator(mp4File, aviFile); if (trackIds[numTracks] != MP4_INVALID_TRACK_ID) { numTracks++; } } if (AVI_audio_bytes(aviFile) > 0) { trackIds[numTracks] = AudioCreator(mp4File, aviFile); if (trackIds[numTracks] != MP4_INVALID_TRACK_ID) { numTracks++; } } AVI_close(aviFile); } trackIds[numTracks] = MP4_INVALID_TRACK_ID; return trackIds;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -