static bool ffmpeg_find_h264_size (ffmpeg_codec_t *ffmpeg, const uint8_t *ud, uint32_t ud_size) { uint32_t offset = 0; do { if (h264_is_start_code(ud + offset)) { if (h264_nal_unit_type(ud + offset) == H264_NAL_TYPE_SEQ_PARAM) { h264_decode_t dec; memset(&dec, 0, sizeof(dec)); if (h264_read_seq_info(ud + offset, ud_size - offset, &dec) == 0) { ffmpeg->m_c->width = dec.pic_width; ffmpeg->m_c->height = dec.pic_height; return true; } } } offset += h264_find_next_start_code(ud + offset, ud_size - offset); } while (offset < ud_size); return false; }
bool CX264VideoEncoder::GetEsConfig (uint8_t **ppEsConfig, uint32_t *pEsConfigLen) { #ifdef DEBUG_H264 debug_message("Getting es config for x264"); #endif CHECK_AND_FREE(Profile()->m_videoMpeg4Config); Profile()->m_videoMpeg4ConfigLength = 0; x264_nal_t *nal; int nal_num; if (x264_encoder_headers(m_h, &nal, &nal_num) != 0) { error_message("x264 - can't create headers"); StopEncoder(); return false; } uint8_t *seqptr = m_vopBuffer; uint8_t *picptr = m_vopBuffer; uint32_t seqlen = 0, piclen = 0; bool found_seq = false, found_pic = false; if (m_vopBuffer == NULL) { m_vopBuffer = (u_int8_t*)malloc(Profile()->m_videoMaxVopSize); } uint8_t *vopBuffer = m_vopBuffer; int vopBufferLen = Profile()->m_videoMaxVopSize; for (int ix = 0; ix < nal_num; ix++) { int i_size; i_size = x264_nal_encode(vopBuffer, &vopBufferLen, 1, &nal[ix]); if (i_size > 0) { bool useit = false; uint header_size = 0; if (h264_is_start_code(vopBuffer)) { header_size = vopBuffer[2] == 1 ? 3 : 4; } if (nal[ix].i_type == H264_NAL_TYPE_SEQ_PARAM) { found_seq = true; seqlen = i_size - header_size; seqptr = vopBuffer + header_size; useit = true; } else if (nal[ix].i_type == H264_NAL_TYPE_PIC_PARAM) { found_pic = true; piclen = i_size - header_size; picptr = vopBuffer + header_size; useit = true; } if (useit) { vopBuffer += i_size; vopBufferLen -= i_size; } } } if (found_seq == false) { error_message("Can't find seq pointer in x264 header"); StopEncoder(); return false; } if (found_pic == false) { error_message("Can't find pic pointer in x264 header"); StopEncoder(); return false; } uint8_t *p = seqptr; if (*p == 0 && p[1] == 0 && (p[2] == 1 || (p[2] == 0 && p[3] == 1))) { if (p[2] == 0) p += 4; else p += 3; } Profile()->m_videoMpeg4ProfileId = p[1] << 16 | p[2] << 8 | p[3]; debug_message("profile id %x", Profile()->m_videoMpeg4ProfileId); char *sprop = NULL; char *base64; base64 = MP4BinaryToBase64(seqptr, seqlen); sprop = strdup(base64); free(base64); base64 = MP4BinaryToBase64(picptr, piclen); sprop = (char *)realloc(sprop, strlen(sprop) + strlen(base64) + 1 + 1); strcat(sprop, ","); strcat(sprop, base64); free(base64); debug_message("sprop %s", sprop); Profile()->m_videoMpeg4Config = (uint8_t *)sprop; Profile()->m_videoMpeg4ConfigLength = strlen(sprop) + 1; StopEncoder(); return true; }
bool CX264VideoEncoder::EncodeImage( const u_int8_t* pY, const u_int8_t* pU, const u_int8_t* pV, u_int32_t yStride, u_int32_t uvStride, bool wantKeyFrame, Duration elapsedDuration, Timestamp srcFrameTimestamp) { //debug_message("encoding at "U64, srcFrameTimestamp); m_push->Push(srcFrameTimestamp); if (m_vopBuffer == NULL) { m_vopBuffer = (u_int8_t*)malloc(Profile()->m_videoMaxVopSize); if (m_vopBuffer == NULL) { error_message("Cannot malloc vop size"); return false; } } m_count++; if (m_count >= m_key_frame_count) { wantKeyFrame = true; m_count = 0; } #ifdef USE_OUR_YUV m_pic_input.img.plane[0] = (uint8_t *)pY; m_pic_input.img.i_stride[0] = yStride; m_pic_input.img.plane[1] = (uint8_t *)pU; m_pic_input.img.i_stride[1] = uvStride; m_pic_input.img.plane[2] = (uint8_t *)pV; m_pic_input.img.i_stride[2] = uvStride; #else CopyYuv(pY, pU, pV, yStride, uvStride, uvStride, m_pic_input.img.plane[0],m_pic_input.img.plane[1],m_pic_input.img.plane[2], m_pic_input.img.i_stride[0],m_pic_input.img.i_stride[1],m_pic_input.img.i_stride[2], Profile()->m_videoWidth, Profile()->m_videoHeight); #endif m_pic_input.i_type = wantKeyFrame ? X264_TYPE_IDR : X264_TYPE_AUTO; m_pic_input.i_pts = srcFrameTimestamp; x264_nal_t *nal; int i_nal; if (x264_encoder_encode(m_h, &nal, &i_nal, &m_pic_input, &m_pic_output) < 0) { error_message("x264_encoder_encode failed"); return false; } CHECK_AND_FREE(m_nal_info); m_nal_info = (h264_nal_buf_t *)malloc(i_nal * sizeof(h264_nal_buf_t)); uint8_t *vopBuffer = m_vopBuffer; int vopBufferLen = m_vopBufferLength; uint32_t loaded = 0; uint32_t nal_on = 0; // read the nals out of the encoder. Nice... for (int ix = 0; ix < i_nal; ix++) { int i_size; bool skip = false; i_size = x264_nal_encode(vopBuffer, &vopBufferLen, 1, &nal[ix]); if (i_size > 0) { m_nal_info[nal_on].nal_length = i_size; m_nal_info[nal_on].nal_offset = loaded; m_nal_info[nal_on].nal_type = nal[ix].i_type; m_nal_info[nal_on].unique = false; uint32_t header = 0; if (h264_is_start_code(vopBuffer)) { header = vopBuffer[2] == 1 ? 3 : 4; } m_nal_info[nal_on].nal_length -= header; m_nal_info[nal_on].nal_offset += header; // we will send picture or sequence header through - let the // sinks decide to send or not if (skip == false) { #ifdef DEBUG_H264 uint8_t nal_type = nal[ix].i_type; if (h264_nal_unit_type_is_slice(nal_type)) { uint8_t stype; h264_find_slice_type(vopBuffer, i_size, &stype, true); debug_message("nal %d - type %u slice type %u %d", ix, nal_type, stype, i_size); } else { debug_message("nal %d - type %u %d", ix, nal_type, i_size); } #endif nal_on++; loaded += i_size; vopBufferLen -= i_size; vopBuffer += i_size; } else { #ifdef DEBUG_H264 debug_message("skipped nal %u", nal[ix].i_type); #endif } } else { error_message("Need to increase vop buffer size by %d", -i_size); } } m_nal_num = nal_on; m_vopBufferLength = loaded; #ifdef DEBUG_H264 debug_message("x264 loaded %d nals, %u len", i_nal, loaded); #endif #ifdef OUTPUT_RAW if (m_vopBufferLength) { fwrite(m_vopBuffer, m_vopBufferLength, 1, m_outfile); } #endif return true; }
/* * 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); }