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::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)); }
/* * read_frame for video - this will try to read the next frame - it * tries to be smart about reading it 1 time if we've already read it * while bookmarking */ void CAviVideoByteStream::read_frame (uint32_t frame_to_read) { uint32_t next_frame_size; if (m_frame_in_buffer == frame_to_read) { m_byte_on = 0; return; } // Haven't already read the next frame, so - get the size, see if // it fits, then read it into the appropriate buffer m_parent->lock_file_mutex(); long temp; AVI_set_video_position(m_parent->get_file(), m_frame_on, &temp); next_frame_size = temp; if (next_frame_size > m_max_frame_size) { m_max_frame_size = next_frame_size; m_buffer = (uint8_t *)realloc(m_buffer, next_frame_size * sizeof(char) + 4); } m_this_frame_size = next_frame_size; AVI_read_frame(m_parent->get_file(), (char *)m_buffer); m_parent->unlock_file_mutex(); m_byte_on = 0; }
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); }
void extract_rgb(info_t *ipipe) { uint8_t *video; avi_t *avifile = NULL; int key, error = 0; long frames, bytes, n; switch (ipipe->magic) { case TC_MAGIC_AVI: if (ipipe->nav_seek_file) { avifile = AVI_open_indexfd(ipipe->fd_in, 0, ipipe->nav_seek_file); } else { avifile = AVI_open_fd(ipipe->fd_in, 1); } if (NULL == avifile) { AVI_print_error("AVI open"); import_exit(1); } frames = AVI_video_frames(avifile); if (ipipe->frame_limit[1] < frames) { frames = ipipe->frame_limit[1]; } if (ipipe->verbose & TC_STATS) { tc_log_msg(__FILE__, "%ld video frames", frames); } video = tc_bufalloc(SIZE_RGB_FRAME); if (!video) { error = 1; break; } AVI_set_video_position(avifile, ipipe->frame_limit[0]); /* FIXME: should this be < rather than <= ? */ for (n = ipipe->frame_limit[0]; n <= frames; n++) { bytes = AVI_read_frame(avifile, video, &key); if (bytes < 0) { error = 1; break; } if (tc_pwrite(ipipe->fd_out, video, bytes) != bytes) { error = 1; break; } } tc_buffree(video); break; case TC_MAGIC_RAW: /* fallthrough */ default: if (ipipe->magic == TC_MAGIC_UNKNOWN) { tc_log_warn(__FILE__, "no file type specified, assuming %s", filetype(TC_MAGIC_RAW)); error = tc_preadwrite(ipipe->fd_in, ipipe->fd_out); break; } } if (error) { tc_log_perror(__FILE__, "error while writing data"); import_exit(error); } }
/* * avi2raw * required arg1 should be the input AVI file * required arg2 should be the output RAW file */ int main(int argc, char** argv) { /* configurable variables from command line */ bool extractVideo = TRUE; /* FALSE implies extract audio */ u_int32_t start = 0; /* secs, start offset */ u_int32_t duration = 0; /* secs, 0 implies entire file */ bool quiet = FALSE; /* internal variables */ char* aviFileName = NULL; char* rawFileName = NULL; avi_t* aviFile = NULL; FILE* rawFile = NULL; int verbose = FALSE; u_int32_t numBytes, totBytes = 0; bool eliminate_short_frames = FALSE; uint32_t short_frames_len; /* begin process command line */ progName = argv[0]; while (1) { int c = -1; int option_index = 0; static struct option long_options[] = { { "audio", 0, 0, 'a' }, { "eliminate-short-frames", optional_argument, 0, 'e'}, { "length", 1, 0, 'l' }, { "quiet", 0, 0, 'q' }, { "start", 1, 0, 's' }, { "video", 0, 0, 'v' }, { "version", 0, 0, 'V'}, { "verbose", 0, 0, 'R'}, { "help", 0, 0, 'h'}, { NULL, 0, 0, 0 } }; c = getopt_long_only(argc, argv, "ael:qs:vVh", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': fprintf(stderr, "%s - %s version %s\n", progName, MPEG4IP_PACKAGE, MPEG4IP_VERSION); fprintf(stderr, "options:\n"); fprintf(stderr, " --audio - extract audio track\n"); fprintf(stderr, " --length <length> - extract <length> secs\n"); fprintf(stderr, " --quiet - quiet mode\n"); fprintf(stderr, " --start <time> - extract from <start> time\n"); fprintf(stderr, " --video - extract video track\n"); fprintf(stderr, " --eliminate-short-frames <bytes> - eliminate short frames of bytes or less - default 4\n"); return 0; case 'a': { extractVideo = FALSE; break; } case 'e': eliminate_short_frames = TRUE; if (optarg) { if (optarg[0] == '=') optarg[0] = ' '; if (sscanf(optarg, "%u", &short_frames_len) != 1) { fprintf(stderr, "%s:bad eliminate length %s\n", progName, optarg); } } else { short_frames_len = 4; } break; case 'l': { /* --length=<secs> */ u_int i; if (sscanf(optarg, "%u", &i) < 1) { fprintf(stderr, "%s: bad length specified: %s\n", progName, optarg); } else { duration = i; } break; } case 'q': { quiet = TRUE; break; } case 's': { /* --start=<secs> */ u_int i; if (sscanf(optarg, "%u", &i) < 1) { fprintf(stderr, "%s: bad start specified: %s\n", progName, optarg); } else { start = i; } break; } case 'v': { extractVideo = TRUE; break; } case '?': break; case 'R': verbose = TRUE; quiet = FALSE; break; case 'V': fprintf(stderr, "%s - %s version %s\n", progName, MPEG4IP_PACKAGE, MPEG4IP_VERSION); return(0); default: fprintf(stderr, "%s: unknown option specified, ignoring: %c\n", progName, c); } } /* check that we have at least two non-option arguments */ if ((argc - optind) < 2) { fprintf(stderr, "usage: %s <avi-file> <raw-file>\n", progName); exit(1); } /* point to the specified file names */ aviFileName = argv[optind++]; rawFileName = argv[optind++]; /* warn about extraneous non-option arguments */ if (optind < argc) { fprintf(stderr, "%s: unknown options specified, ignoring: ", progName); while (optind < argc) { fprintf(stderr, "%s ", argv[optind++]); } fprintf(stderr, "\n"); } /* end processing of command line */ /* open the AVI file */ aviFile = AVI_open_input_file(aviFileName, TRUE); if (aviFile == NULL) { fprintf(stderr, "%s: error %s: %s\n", progName, aviFileName, AVI_strerror()); exit(4); } if (!quiet) { fprintf(stderr, "%s - %s version %s\n", progName, MPEG4IP_PACKAGE, MPEG4IP_VERSION); } /* open the RAW file */ rawFile = fopen(rawFileName, "wb"); if (rawFile == NULL) { fprintf(stderr, "%s: error opening %s: %s\n", progName, rawFileName, strerror(errno)); exit(5); } if (extractVideo) { double videoFrameRate = AVI_video_frame_rate(aviFile); u_int32_t numVideoFrames = AVI_video_frames(aviFile); u_int32_t fileDuration = ceil(numVideoFrames / videoFrameRate); u_int32_t numDesiredVideoFrames; u_int32_t videoFramesRead = 0; u_int32_t emptyFramesRead = 0; /* get a buffer large enough to handle a frame of raw SDTV */ u_char* buf = (u_char*)malloc(768 * 576 * 4); if (duration) { numDesiredVideoFrames = duration * videoFrameRate; } else { numDesiredVideoFrames = numVideoFrames; } if (buf == NULL) { fprintf(stderr, "%s: error allocating memory: %s\n", progName, strerror(errno)); exit(6); } /* check that start offset is valid */ if (start > fileDuration) { fprintf(stderr, "%s: specified start is past the end of the file\n", progName); exit(7); } if (AVI_seek_start(aviFile)) { fprintf(stderr, "%s: bad seek: %s\n", progName, AVI_strerror()); exit(8); } if (AVI_set_video_position(aviFile, (long) ROUND(start * videoFrameRate), NULL)) { fprintf(stderr, "%s: bad seek: %s\n", progName, AVI_strerror()); exit(9); } #ifdef DEBUG_H264 h264_decode_t dec; #endif while (TRUE) { numBytes = AVI_read_frame(aviFile, (char *)buf); /* read error */ if (numBytes < 0) { break; } totBytes += numBytes; videoFramesRead++; if (verbose) { printf("frame %d - len %u total %u\n", videoFramesRead, numBytes, totBytes); } /* * note some capture programs * insert a zero length frame occasionally * hence numBytes == 0, but we're not a EOF */ if ((eliminate_short_frames && numBytes > short_frames_len) || (eliminate_short_frames == FALSE && numBytes)) { // test #ifdef DEBUG_H264 uint32_t offset = 0, read; do { if (h264_is_start_code(buf + offset)) { int ret = h264_detect_boundary(buf + offset, numBytes - offset, &dec); printf(" frame offset %d nal type %d slice %d %d\n", offset, dec.nal_unit_type, dec.slice_type, ret); } read = h264_find_next_start_code(buf + offset, numBytes - offset); offset += read; } while (read != 0 && offset < numBytes); #endif if (fwrite(buf, 1, numBytes, rawFile) != numBytes) { fprintf(stderr, "%s: error writing %s: %s\n", progName, rawFileName, strerror(errno)); break; } } else { emptyFramesRead++; } if (videoFramesRead >= numDesiredVideoFrames) { break; } } if (verbose) { printf("read %u video bytes\n", totBytes); } if (numBytes < 0) { printf("%s: error reading %s, frame %d, %s\n", progName, aviFileName, videoFramesRead + 1, AVI_strerror()); } if (videoFramesRead < numDesiredVideoFrames) { fprintf(stderr, "%s: warning: could only extract %u seconds of video (%u of %u frames)\n", progName, (unsigned int)ceil(videoFramesRead / videoFrameRate), videoFramesRead, numDesiredVideoFrames); } if (emptyFramesRead) { fprintf(stderr, "%s: warning: %u zero length frames ignored\n", progName, emptyFramesRead); } if (!quiet) { printf("%u video frames written\n", videoFramesRead - emptyFramesRead); } /* cleanup */ free(buf); } else { /* extract audio */ u_int32_t audioBytesRead = 0; u_char *buf = (u_char*) malloc(8*1024); u_int32_t numDesiredAudioBytes = AVI_audio_bytes(aviFile); u_int32_t audioBytesPerSec = 0; if (start != 0) { u_int32_t numAudioBytes = numDesiredAudioBytes; u_int32_t fileDuration; audioBytesPerSec = AVI_audio_rate(aviFile) * ((AVI_audio_bits(aviFile) + 7) / 8) * AVI_audio_channels(aviFile); fileDuration = ceil(numAudioBytes / audioBytesPerSec); numDesiredAudioBytes = duration * audioBytesPerSec; /* check that start offset is valid */ if (start > fileDuration) { fprintf(stderr, "%s: specified start is past the end of the file\n", progName); exit(7); } if (AVI_seek_start(aviFile)) { fprintf(stderr, "%s: bad seek: %s\n", progName, AVI_strerror()); exit(8); } if (AVI_set_audio_position(aviFile, start * audioBytesPerSec)) { fprintf(stderr, "%s: bad seek: %s\n", progName, AVI_strerror()); exit(9); } } else { if (AVI_seek_start(aviFile)) { fprintf(stderr, "%s: bad seek: %s\n", progName, AVI_strerror()); exit(8); } if (AVI_set_audio_position(aviFile, 0)) { fprintf(stderr, "%s: bad seek: %s\n", progName, AVI_strerror()); exit(9); } } while ((numBytes = AVI_read_audio(aviFile, (char *)buf, sizeof(buf))) > 0) { if (fwrite(buf, 1, numBytes, rawFile) != numBytes) { fprintf(stderr, "%s: error writing %s: %s\n", progName, rawFileName, strerror(errno)); break; } audioBytesRead += numBytes; if (numDesiredAudioBytes && audioBytesRead >= numDesiredAudioBytes) { break; } } if (verbose) { printf("read %u audio bytes\n", audioBytesRead); } if (duration && audioBytesRead < numDesiredAudioBytes) { fprintf(stderr, "%s: warning: could only extract %u seconds of audio\n", progName, audioBytesPerSec == 0 ? audioBytesRead : audioBytesRead / audioBytesPerSec); } if (!quiet && AVI_audio_bits(aviFile) != 0) { printf("%u audio samples written\n", audioBytesRead / ((AVI_audio_bits(aviFile) + 7) / 8)); } } /* cleanup */ AVI_close(aviFile); fclose(rawFile); return(0); }