void avi_reader_c::create_video_packetizer() { size_t i; mxverb_tid(4, m_ti.m_fname, 0, "frame sizes:\n"); for (i = 0; i < m_max_video_frames; i++) { m_bytes_to_process += AVI_frame_size(m_avi, i); mxverb(4, boost::format(" %1%: %2%\n") % i % AVI_frame_size(m_avi, i)); } if (m_avi->bitmap_info_header) { m_ti.m_private_data = memory_c::clone(m_avi->bitmap_info_header, get_uint32_le(&m_avi->bitmap_info_header->bi_size)); mxverb(4, boost::format("track extra data size: %1%\n") % (m_ti.m_private_data->get_size() - sizeof(alBITMAPINFOHEADER))); if (sizeof(alBITMAPINFOHEADER) < m_ti.m_private_data->get_size()) mxverb(4, boost::format(" %1%\n") % to_hex(m_ti.m_private_data->get_buffer() + sizeof(alBITMAPINFOHEADER), m_ti.m_private_data->get_size() - sizeof(alBITMAPINFOHEADER))); } const char *codec = AVI_video_compressor(m_avi); if (mpeg4::p2::is_v3_fourcc(codec)) m_divx_type = DIVX_TYPE_V3; else if (mpeg4::p2::is_fourcc(codec)) m_divx_type = DIVX_TYPE_MPEG4; if (map_has_key(m_ti.m_default_durations, 0)) m_fps = 1000000000.0 / m_ti.m_default_durations[0]; else if (map_has_key(m_ti.m_default_durations, -1)) m_fps = 1000000000.0 / m_ti.m_default_durations[-1]; m_ti.m_id = 0; // ID for the video track. if (DIVX_TYPE_MPEG4 == m_divx_type) create_mpeg4_p2_packetizer(); else if (mpeg4::p10::is_avc_fourcc(codec) && !hack_engaged(ENGAGE_ALLOW_AVC_IN_VFW_MODE)) create_mpeg4_p10_packetizer(); else if (mpeg1_2::is_fourcc(get_uint32_le(codec))) create_mpeg1_2_packetizer(); else if (FOURCC('V', 'P', '8', '0') == get_uint32_be(codec)) create_vp8_packetizer(); else create_standard_video_packetizer(); }
/* * Class: com_mcxiaoke_ndk_Native * Method: init * Signature: (J)J */ JNIEXPORT jlong JNICALL Java_com_mcxiaoke_ndk_Native_init (JNIEnv *env, jclass clazz, jlong avi) { Instance* instance = 0; long frameSize = AVI_frame_size((avi_t*) avi, 0); if (0 >= frameSize) { ThrowException(env, "java/lang/RuntimeException", "Unable to get the frame size."); goto exit; } instance = new Instance(); if (0 == instance) { ThrowException(env, "java/lang/RuntimeException", "Unable to allocate instance."); goto exit; } instance->buffer = (char*) malloc(frameSize); if (0 == instance->buffer) { ThrowException(env, "java/lang/RuntimeException", "Unable to allocate buffer."); delete instance; instance = 0; } exit: return (jlong) instance; }
void avi_reader_c::extended_identify_mpeg4_l2(std::vector<std::string> &extended_info) { int size = AVI_frame_size(m_avi, 0); if (0 >= size) return; memory_cptr af_buffer = memory_c::alloc(size); unsigned char *buffer = af_buffer->get_buffer(); int dummy_key; AVI_read_frame(m_avi, reinterpret_cast<char *>(buffer), &dummy_key); uint32_t par_num, par_den; if (mpeg4::p2::extract_par(buffer, size, par_num, par_den)) { int width = AVI_video_width(m_avi); int height = AVI_video_height(m_avi); float aspect_ratio = static_cast<float>(width) * par_num / height / par_den; int disp_width, disp_height; if (aspect_ratio > (static_cast<float>(width) / height)) { disp_width = irnd(height * aspect_ratio); disp_height = height; } else { disp_width = width; disp_height = irnd(width / aspect_ratio); } extended_info.push_back((boost::format("display_dimensions:%1%x%2%") % disp_width % disp_height).str()); } }
void avi_reader_c::set_avc_nal_size_size(mpeg4_p10_es_video_packetizer_c *ptzr) { m_avc_nal_size_size = ptzr->get_nalu_size_length(); for (size_t i = 0; i < m_max_video_frames; ++i) { int size = AVI_frame_size(m_avi, i); if (0 == size) continue; memory_cptr buffer = memory_c::alloc(size); AVI_set_video_position(m_avi, i); int key = 0; size = AVI_read_frame(m_avi, reinterpret_cast<char *>(buffer->get_buffer()), &key); if ( (4 <= size) && ( (get_uint32_be(buffer->get_buffer()) == NALU_START_CODE) || (get_uint24_be(buffer->get_buffer()) == NALU_START_CODE))) m_avc_nal_size_size = -1; break; } AVI_set_video_position(m_avi, 0); }
void avi_reader_c::extended_identify_mpeg4_l2(mtx::id::info_c &info) { int size = AVI_frame_size(m_avi, 0); if (0 >= size) return; memory_cptr af_buffer = memory_c::alloc(size); unsigned char *buffer = af_buffer->get_buffer(); int dummy_key; AVI_read_frame(m_avi, reinterpret_cast<char *>(buffer), &dummy_key); uint32_t par_num, par_den; if (mpeg4::p2::extract_par(buffer, size, par_num, par_den)) { auto aspect_ratio = static_cast<double>(m_video_width) * par_num / m_video_height / par_den; int disp_width, disp_height; if (aspect_ratio > (static_cast<double>(m_video_width) / m_video_height)) { disp_width = std::llround(m_video_height * aspect_ratio); disp_height = m_video_height; } else { disp_width = m_video_width; disp_height = std::llround(m_video_width / aspect_ratio); } info.add(mtx::id::display_dimensions, boost::format("%1%x%2%") % disp_width % disp_height); } }
void avi_reader_c::debug_dump_video_index() { int num_video_frames = AVI_video_frames(m_avi), i; mxinfo(boost::format("AVI video index dump: %1% entries; frame rate: %2%\n") % num_video_frames % m_fps); for (i = 0; num_video_frames > i; ++i) mxinfo(boost::format(" %1%: %2% bytes\n") % i % AVI_frame_size(m_avi, i)); }
void avi_reader_c::create_mpeg1_2_packetizer() { std::shared_ptr<M2VParser> m2v_parser(new M2VParser); m2v_parser->SetProbeMode(); if (m_ti.m_private_data && (m_ti.m_private_data->get_size() < sizeof(alBITMAPINFOHEADER))) m2v_parser->WriteData(m_ti.m_private_data->get_buffer() + sizeof(alBITMAPINFOHEADER), m_ti.m_private_data->get_size() - sizeof(alBITMAPINFOHEADER)); unsigned int frame_number = 0; unsigned int state = m2v_parser->GetState(); while ((frame_number < std::min(m_max_video_frames, 100u)) && (MPV_PARSER_STATE_FRAME != state)) { ++frame_number; int size = AVI_frame_size(m_avi, frame_number - 1); if (0 == size) continue; AVI_set_video_position(m_avi, frame_number - 1); memory_cptr buffer = memory_c::alloc(size); int key = 0; int num_read = AVI_read_frame(m_avi, reinterpret_cast<char *>(buffer->get_buffer()), &key); if (0 >= num_read) continue; m2v_parser->WriteData(buffer->get_buffer(), num_read); state = m2v_parser->GetState(); } AVI_set_video_position(m_avi, 0); if (MPV_PARSER_STATE_FRAME != state) mxerror_tid(m_ti.m_fname, 0, Y("Could not extract the sequence header from this MPEG-1/2 track.\n")); MPEG2SequenceHeader seq_hdr = m2v_parser->GetSequenceHeader(); std::shared_ptr<MPEGFrame> frame(m2v_parser->ReadFrame()); if (!frame) mxerror_tid(m_ti.m_fname, 0, Y("Could not extract the sequence header from this MPEG-1/2 track.\n")); int display_width = ((0 >= seq_hdr.aspectRatio) || (1 == seq_hdr.aspectRatio)) ? seq_hdr.width : static_cast<int>(seq_hdr.height * seq_hdr.aspectRatio); MPEGChunk *raw_seq_hdr = m2v_parser->GetRealSequenceHeader(); if (raw_seq_hdr) m_ti.m_private_data = memory_c::clone(raw_seq_hdr->GetPointer(), raw_seq_hdr->GetSize()); else m_ti.m_private_data.reset(); m_vptzr = add_packetizer(new mpeg1_2_video_packetizer_c(this, m_ti, m2v_parser->GetMPEGVersion(), seq_hdr.frameOrFieldRate, seq_hdr.width, seq_hdr.height, display_width, seq_hdr.height, false)); show_packetizer_info(0, PTZR(m_vptzr)); }
void avi_reader_c::debug_dump_video_index() { int num_video_frames = AVI_video_frames(m_avi), i; mxinfo(boost::format("AVI video index dump: %1% entries; frame rate: %2%\n") % num_video_frames % m_fps); for (i = 0; num_video_frames > i; ++i) { int key = 0; AVI_read_frame(m_avi, nullptr, &key); mxinfo(boost::format(" %1%: %2% bytes; key: %3%\n") % i % AVI_frame_size(m_avi, i) % key); } AVI_set_video_position(m_avi, 0); }
file_status_e avi_reader_c::read_video() { if (m_video_frames_read >= m_max_video_frames) return flush_packetizer(m_vptzr); memory_cptr chunk; int key = 0; int old_video_frames_read = m_video_frames_read; int size, num_read; int dropped_frames_here = 0; do { size = AVI_frame_size(m_avi, m_video_frames_read); chunk = memory_c::alloc(size); num_read = AVI_read_frame(m_avi, reinterpret_cast<char *>(chunk->get_buffer()), &key); ++m_video_frames_read; if (0 > num_read) { // Error reading the frame: abort m_video_frames_read = m_max_video_frames; return flush_packetizer(m_vptzr); } else if (0 == num_read) ++dropped_frames_here; } while ((0 == num_read) && (m_video_frames_read < m_max_video_frames)); if (0 == num_read) // This is only the case if the AVI contains dropped frames only. return flush_packetizer(m_vptzr); size_t i; for (i = m_video_frames_read; i < m_max_video_frames; ++i) { if (0 != AVI_frame_size(m_avi, i)) break; int dummy_key; AVI_read_frame(m_avi, nullptr, &dummy_key); ++dropped_frames_here; ++m_video_frames_read; } int64_t timestamp = static_cast<int64_t>(static_cast<int64_t>(old_video_frames_read) * 1000000000ll / m_fps); int64_t duration = static_cast<int64_t>(static_cast<int64_t>(dropped_frames_here + 1) * 1000000000ll / m_fps); m_dropped_video_frames += dropped_frames_here; // AVC with framed packets (without NALU start codes but with length fields) // or non-AVC video track? if (0 >= m_avc_nal_size_size) PTZR(m_vptzr)->process(new packet_t(chunk, timestamp, duration, key ? VFT_IFRAME : VFT_PFRAMEAUTOMATIC, VFT_NOBFRAME)); else { // AVC video track without NALU start codes. Re-frame with NALU start codes. int offset = 0; while ((offset + m_avc_nal_size_size) < num_read) { int nalu_size = get_uint_be(chunk->get_buffer() + offset, m_avc_nal_size_size); offset += m_avc_nal_size_size; if ((offset + nalu_size) > num_read) break; memory_cptr nalu = memory_c::alloc(4 + nalu_size); put_uint32_be(nalu->get_buffer(), NALU_START_CODE); memcpy(nalu->get_buffer() + 4, chunk->get_buffer() + offset, nalu_size); offset += nalu_size; PTZR(m_vptzr)->process(new packet_t(nalu, timestamp, duration, key ? VFT_IFRAME : VFT_PFRAMEAUTOMATIC, VFT_NOBFRAME)); } } m_bytes_processed += num_read; return m_video_frames_read >= m_max_video_frames ? flush_packetizer(m_vptzr) : FILE_STATUS_MOREDATA; }