📄 xvid_file.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. 2002. All Rights Reserved. * * Contributor(s): * Bill May wmay@cisco.com *//* * xvid_file.cpp * Read a raw file for xvid. */#include "ourxvid.h"#include "xvid.h"#include "divx4.h"/* * xvid_find_header * Search buffer to find the next start code */static int xvid_find_header (xvid_codec_t *xvid, uint32_t start_offset){ for (uint32_t ix = start_offset; ix + 4 < xvid->m_buffer_size; ix++) { if ((xvid->m_buffer[ix] == 0) && (xvid->m_buffer[ix + 1] == 0)) { if (xvid->m_buffer[ix + 2] == 1) return ix; if (((xvid->m_buffer[ix + 2] & 0xfc) == 0x80) && ((xvid->m_buffer[ix + 3] & 0x3) == 0x02)) { xvid->m_short_headers = 1; return ix; } } } return -1;}/* * xvid_reset_buffer * Move end of buffer to beginning, fill in rest of buffer */static int xvid_reset_buffer (xvid_codec_t *xvid){ uint32_t diff, read; if (xvid->m_buffer_size > xvid->m_buffer_on) { diff = xvid->m_buffer_size - xvid->m_buffer_on; memmove(xvid->m_buffer, &xvid->m_buffer[xvid->m_buffer_on], diff); } else diff = 0; xvid->m_buffer_size = diff; read = fread(xvid->m_buffer + diff, 1, xvid->m_buffer_size_max - diff, xvid->m_ifile); xvid->m_buffer_on = 0; if (read <= 0) { if (xvid->m_buffer_size < 4) xvid->m_buffer_size = 0; return -1; } xvid->m_buffer_size += read; if (xvid->m_buffer_size < 4) xvid->m_buffer_size = 0; return diff;}/* * xvid_buffer_load * Make sure we have at least 1 full VOP frame in the buffer */static int xvid_buffer_load (xvid_codec_t *xvid, uint8_t *ftype) { int next_hdr, left, value; if (xvid->m_buffer_on + 3 >= xvid->m_buffer_size) { if (xvid_reset_buffer(xvid) < 0) return -1; } next_hdr = xvid_find_header(xvid, xvid->m_buffer_on); if (next_hdr < 0) return -1; // We've got the first header pointed to by m_buffer_on xvid->m_buffer_on = next_hdr; // Is it a VOP header ? If not, find the first VOP header if (xvid->m_short_headers == 0 && xvid->m_buffer[next_hdr + 3] != 0xb6) { value = 0; do { // Increment when we've got a header pointed to by next_hdr if (value >= 0) next_hdr += 4; value = xvid_find_header(xvid, next_hdr); if (value < 0) { if (xvid->m_buffer_on == 0 && xvid->m_buffer_size == xvid->m_buffer_size_max) { // weirdness has happened. We've got a full buffer of // headers, no frames return -1; } left = xvid_reset_buffer(xvid); if (left < 0) { // No more new data - we've reached the end... return xvid->m_buffer_size; } // okay - this case is gross - we'll start checking from the // beginning next_hdr = left - 4; } else { next_hdr = value; } } while (value < 0 || xvid->m_buffer[next_hdr + 3] != 0xb6); } // next_hdr contains the location of the first VOP. // Record the file type (top 2 bits) after 00 00 01 b6 if (xvid->m_short_headers == 0) *ftype = (xvid->m_buffer[next_hdr + 4] >> 6) & 0x3; else *ftype = (xvid->m_buffer[next_hdr + 4] >> 1) & 0x1; // Find the next header. value = xvid_find_header(xvid, next_hdr + 4); if (value >= 0) { // Cool - it's in the header... return value; } // // Not in the header - reset the buffer, then continue search // value = xvid->m_buffer_size - xvid->m_buffer_on; left = xvid_reset_buffer(xvid); if (left < 0) return xvid->m_buffer_size; value = xvid_find_header(xvid, value); if (value >= 0) { return value; } // We don't have enough read in... Go forward while (xvid->m_buffer_size_max < 65535) { int old, readsize; xvid->m_buffer = (uint8_t *)realloc(xvid->m_buffer, xvid->m_buffer_size_max + 1024); readsize = fread(&xvid->m_buffer[xvid->m_buffer_size_max], 1, 1024, xvid->m_ifile); if (readsize <= 0) { return (xvid->m_buffer_size - xvid->m_buffer_on); } old = xvid->m_buffer_size; xvid->m_buffer_size += readsize; xvid->m_buffer_size_max += 1024; value = xvid_find_header(xvid, old - 4); if (value >= 0) return value; } return -1;}/* * xvid_file_check * Check the file. If it's a .xvid file, look for the VOL, and record * where the I frames are. */codec_data_t *xvid_file_check (lib_message_func_t message, const char *name, double *max, char *desc[4]){ int len; xvid_codec_t *xvid; uint32_t framecount = 0; uint64_t calc; XVID_INIT_PARAM xvid_param; /* * Compare with .xvid extension */ len = strlen(name); if (!((strcasecmp(name + len - 5, ".divx") == 0) || (strcasecmp(name + len - 5, ".xvid") == 0) || (strcasecmp(name + len - 5, ".h263") == 0))) { return NULL; } /* * Malloc the xvid structure, init some variables */ xvid = MALLOC_STRUCTURE(xvid_codec_t); memset(xvid, 0, sizeof(*xvid)); xvid_param.cpu_flags = 0; xvid_init(NULL, 0, &xvid_param, NULL); XVID_DEC_PARAM dec_param; xvid_decore(NULL, XVID_DEC_ALLOC, &dec_param, NULL); xvid->m_xvid_handle = dec_param.handle; xvid->m_decodeState = XVID_STATE_VO_SEARCH; xvid->m_ifile = fopen(name, FOPEN_READ_BINARY); if (xvid->m_ifile == NULL) { free(xvid); return NULL; } xvid->m_buffer = (uint8_t *)malloc(16 * 1024); xvid->m_buffer_size_max = 16 * 1024; xvid->m_fpos = new CFilePosRecorder(); xvid->m_fpos->record_point(0, 0, 0); /* * Start searching the file, find the VOL, mark the I frames */ int havevol = 0; int nextframe; uint8_t ftype; nextframe = xvid_buffer_load(xvid, &ftype); do { if (havevol == 0) { XVID_DEC_FRAME frame; XVID_DEC_PARAM param; frame.bitstream = (void *)&xvid->m_buffer[xvid->m_buffer_on]; frame.length = xvid->m_buffer_size - xvid->m_buffer_on; int ret = xvid_decore(xvid->m_xvid_handle, XVID_DEC_FIND_VOL, &frame, ¶m); if (ret == XVID_ERR_OK) { havevol = 1; message(LOG_DEBUG, "xvid", "Found vol in xvid file"); // we really need the frames per second from the timestamps... xvid->m_buffer_on = nextframe; } else xvid->m_buffer_on = xvid->m_buffer_size - 3; } else { // If we have an I_VOP, mark it. if (ftype == 0) { calc = framecount * 1000; calc /= 30; //message(LOG_DEBUG, "xvid", "I frame at %u "LLU, framecount, calc); xvid->m_fpos->record_point(ftell(xvid->m_ifile) - xvid->m_buffer_size - xvid->m_buffer_on, calc, framecount); } xvid->m_buffer_on = nextframe; } framecount++; nextframe = xvid_buffer_load(xvid, &ftype); } while (nextframe != -1); if (havevol == 0) { xvid_clean_up(xvid); return NULL; } *max = (double)framecount / 30.0; //(double)mp4_hdr.fps; rewind(xvid->m_ifile); return ((codec_data_t *)xvid); }/* * xvid_file_next_frame * Read in the next frame, return timestamp */int xvid_file_next_frame (codec_data_t *your_data, uint8_t **buffer, uint64_t *ts){ xvid_codec_t *xvid; int next_hdr, value; xvid = (xvid_codec_t *)your_data; // start at the next header next_hdr = xvid_find_header(xvid, xvid->m_buffer_on); if (next_hdr < 0) { next_hdr = xvid_reset_buffer(xvid); if (next_hdr < 0) { xvid->m_buffer_on = xvid->m_buffer_size; return 0; } next_hdr = xvid_find_header(xvid, next_hdr); if (next_hdr < 0) { xvid->m_buffer_on = xvid->m_buffer_size; return 0; } } xvid->m_buffer_on = next_hdr; value = 0; // find first vop -short headers are always next frame if (xvid->m_short_headers == 0) { while (xvid->m_buffer[next_hdr + 3] != 0xb6) { value = xvid_find_header(xvid, next_hdr + 4); if (value < 0) { value = xvid_reset_buffer(xvid); if (value < 0) { xvid->m_buffer_on = xvid->m_buffer_size; return 0; } next_hdr = xvid_find_header(xvid, value - 4); } else { next_hdr = value; } } } // find the next start code, so we have 1 frame in buffer // Don't have to worry about going past end of buffer, or buffer length // not being enough - we've fixed that problem when initially reading // in the file. value = xvid_find_header(xvid, next_hdr + 4); if (value < 0) { xvid_reset_buffer(xvid); value = xvid_find_header(xvid, 4); } *ts = (xvid->m_frame_on * M_LLU) / 30; //mp4_hdr.fps; *buffer = &xvid->m_buffer[xvid->m_buffer_on]; xvid->m_frame_on++; return xvid->m_buffer_size - xvid->m_buffer_on;}/* * xvid_file_used_for_frame * Tell how many bytes we used */void xvid_file_used_for_frame (codec_data_t *your, uint32_t bytes){ xvid_codec_t *xvid = (xvid_codec_t *)your; xvid->m_buffer_on += bytes; //xvid->m_vft->log_msg(LOG_DEBUG, "xvid", "used %u bytes", bytes);}/* * xvid_file_seek_to - find the closest time to ts, start from * there */int xvid_file_seek_to (codec_data_t *your, uint64_t ts){ xvid_codec_t *xvid = (xvid_codec_t *)your; const frame_file_pos_t *fpos = xvid->m_fpos->find_closest_point(ts); xvid->m_frame_on = fpos->frames; xvid->m_buffer_on = 0; xvid->m_buffer_size = 0; fseek(xvid->m_ifile, fpos->file_position, SEEK_SET); xvid_reset_buffer(xvid); return 0;}/* * xvid_file_eof * see if we've hit the end of the file */int xvid_file_eof (codec_data_t *ifptr){ xvid_codec_t *xvid = (xvid_codec_t *)ifptr; return xvid->m_buffer_on == xvid->m_buffer_size && feof(xvid->m_ifile);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -