#include "Scene.h" #ifndef VIDEO_OPENLIB #ifndef USE_WMV #define NO_AVI_TO_FLV #endif #endif #ifndef NO_AVI_TO_FLV #pragma comment(lib, "..\\LIBS\\ENCDEC\\avcodec-51.lib") #pragma comment(lib, "..\\LIBS\\ENCDEC\\avdevice-52.lib") #pragma comment(lib, "..\\LIBS\\ENCDEC\\avformat-52.lib") #pragma comment(lib, "..\\LIBS\\ENCDEC\\avutil-49.lib") extern "C" { #include "libavformat/avformat.h" #include "libavutil/avutil.h" #include "libavcodec/avcodec.h" }; #ifndef USE_WMV #define STREAM_FRAME_RATE 25 /* 25 images/s */ #else #define STREAM_FRAME_RATE 30 /* 30 images/s */ #endif #define STREAM_FRAME_TIME (1000/STREAM_FRAME_RATE) /* 25 images/s */ #define FILE_FORMAT "flv" // "avi" // "mpeg" // #define VIDEO_ENCODER CODEC_ID_FLV1 //CODEC_ID_H263 // CODEC_ID_WMV2 //CODEC_ID_MPEG2VIDEO //CODEC_ID_MPEG4 //CODEC_ID_MPEG1VIDEO // #define AUDIO_ENCODER CODEC_ID_MP3 //CODEC_ID_MP2 //CODEC_ID_AAC //CODEC_ID_MP3 // #define STREAM_PIX_FMT PIX_FMT_YUV420P #define NB_CHANNELS 2 typedef struct AVStreamData_ { int streamIndex; uint32_t bufferSize; uint8_t *pBuffer; AVFrame *pFrame; // if video AVCodecContext *pCodecCtx; AVCodec *pCodec; } AVStreamData; typedef struct AVIData_ { AVFormatContext *pFormatCtx; AVStreamData vd; AVStreamData sd; } AVIData; float PourcentConvertion; void FreeAVIData(AVIData *data, int dst) { if (data->vd.streamIndex != -1) { avcodec_close(data->vd.pCodecCtx); av_free(data->vd.pBuffer); } if (data->sd.streamIndex != -1) { avcodec_close(data->sd.pCodecCtx); CC_free(data->sd.pBuffer); } if (data->pFormatCtx) { if (dst && data->pFormatCtx->pb) { av_write_trailer(data->pFormatCtx); url_fclose(data->pFormatCtx->pb); } else if (!dst) av_close_input_file(data->pFormatCtx); if(dst) av_free(data->pFormatCtx); } } int InitSrc(char *src, AVIData *data) { int error; error = av_open_input_file(&data->pFormatCtx, (char *)src, NULL, 0, NULL); if (error < 0) return 0; error = av_find_stream_info(data->pFormatCtx); if (error < 0) return 0; data->vd.streamIndex = -1; for(u32 i=0; ipFormatCtx->nb_streams && data->vd.streamIndex == -1; i++) if(data->pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) data->vd.streamIndex=i; if (data->vd.streamIndex < 0) return 0; data->sd.streamIndex = -1; for(u32 i=0; ipFormatCtx->nb_streams && data->sd.streamIndex == -1; i++) if(data->pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) data->sd.streamIndex=i; data->vd.pCodecCtx = data->pFormatCtx->streams[data->vd.streamIndex]->codec; data->vd.pCodec = avcodec_find_decoder(data->vd.pCodecCtx->codec_id); if (!data->vd.pCodec) return 0; if(data->vd.pCodec->capabilities & CODEC_CAP_TRUNCATED) data->vd.pCodecCtx->flags |= CODEC_FLAG_TRUNCATED; if (avcodec_open(data->vd.pCodecCtx, data->vd.pCodec) < 0) return 0; data->vd.pFrame = avcodec_alloc_frame(); if (!data->vd.pFrame) return 0; data->vd.bufferSize = avpicture_get_size(STREAM_PIX_FMT, data->vd.pCodecCtx->width, data->vd.pCodecCtx->height); data->vd.pBuffer = (uint8_t *)av_malloc(data->vd.bufferSize); if (!data->vd.pBuffer) return 0; avpicture_fill((AVPicture *)data->vd.pFrame, data->vd.pBuffer, STREAM_PIX_FMT, data->vd.pCodecCtx->width, data->vd.pCodecCtx->height); if (data->sd.streamIndex != -1) { data->sd.pCodecCtx = data->pFormatCtx->streams[data->sd.streamIndex]->codec; data->sd.pCodec = avcodec_find_decoder(data->sd.pCodecCtx->codec_id); if (avcodec_open(data->sd.pCodecCtx, data->sd.pCodec) < 0) return 0; data->sd.bufferSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; data->sd.pBuffer = (uint8_t *)CC_malloc(data->sd.bufferSize); } return 1; } int InitDst(char *dst, AVIData *data, int width, int height, u32 snd) { int error; AVCodec *videoEncoder; AVCodec *audioEncoder; videoEncoder= avcodec_find_encoder(VIDEO_ENCODER); audioEncoder= avcodec_find_encoder(AUDIO_ENCODER); if (!videoEncoder || !audioEncoder) return 0; AVOutputFormat *fmt = guess_format(FILE_FORMAT, NULL, NULL); AVStream *stream; if (!fmt) return 0; data->pFormatCtx = av_alloc_format_context(); data->pFormatCtx->oformat = fmt; strcpy(data->pFormatCtx->filename, dst); error = av_set_parameters(data->pFormatCtx, NULL); if (error < 0) return 0; dump_format(data->pFormatCtx, 0, dst, 1); stream = av_new_stream(data->pFormatCtx, 0); data->vd.pCodecCtx = stream->codec; data->vd.pCodecCtx->codec_id = videoEncoder->id; data->vd.pCodecCtx->codec_type = CODEC_TYPE_VIDEO; /* put sample parameters */ data->vd.pCodecCtx->bit_rate = 1000000; data->vd.pCodecCtx->me_method = 1; /* resolution must be a multiple of two */ data->vd.pCodecCtx->width = width; data->vd.pCodecCtx->height = height; /* time base: this is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented. for fixed-fps content, timebase should be 1/framerate and timestamp increments should be identically 1. */ data->vd.pCodecCtx->time_base.den = STREAM_FRAME_RATE; data->vd.pCodecCtx->time_base.num = 1; data->vd.pCodecCtx->gop_size = 12; /* emit one intra frame every gop_size frames at most */ data->vd.pCodecCtx->pix_fmt = STREAM_PIX_FMT; /* Special case */ if (data->vd.pCodecCtx->codec_id == CODEC_ID_MPEG2VIDEO) data->vd.pCodecCtx->max_b_frames = 2; if (data->vd.pCodecCtx->codec_id == CODEC_ID_MPEG1VIDEO) data->vd.pCodecCtx->mb_decision = 2; error = avcodec_open(data->vd.pCodecCtx, videoEncoder); if (error < 0) return 0; data->vd.pFrame = avcodec_alloc_frame(); if (!data->vd.pFrame) return 0; data->vd.bufferSize = avpicture_get_size(STREAM_PIX_FMT, width, height); data->vd.pBuffer = (uint8_t *)av_malloc(data->vd.bufferSize); if (!data->vd.pBuffer) return 0; avpicture_fill((AVPicture *)data->vd.pFrame, data->vd.pBuffer, STREAM_PIX_FMT, width, height); if (snd) { stream = av_new_stream(data->pFormatCtx, 1); data->sd.pCodecCtx = stream->codec; data->sd.pCodecCtx->codec_id = audioEncoder->id; data->sd.pCodecCtx->codec_type = CODEC_TYPE_AUDIO; /* put sample parameters */ data->sd.pCodecCtx->bit_rate = SND_BIT_RATE; data->sd.pCodecCtx->sample_rate = SND_SAMPLES; data->sd.pCodecCtx->channels = NB_CHANNELS; error = avcodec_open(data->sd.pCodecCtx, audioEncoder); if (error < 0) return 0; data->sd.bufferSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; data->sd.pBuffer = (uint8_t *)CC_malloc(data->sd.bufferSize); } else data->sd.streamIndex = -1; error = url_fopen(&data->pFormatCtx->pb, dst, URL_WRONLY); if (error < 0) return 0; error = av_write_header(data->pFormatCtx); if (error < 0) return 0; return 1; } int AVIToFlv(char *src, char *dst, bool *Aborted) { int error; int useSound = 0; av_register_all(); AVIData srcData; AVIData dstData; if (!InitSrc(src, &srcData)) return 0; useSound = srcData.sd.streamIndex != -1; if (!InitDst(dst, &dstData, srcData.vd.pCodecCtx->width, srcData.vd.pCodecCtx->height, useSound)) return 0; //ByteIOContext *pb = dstData.pFormatCtx->pb; //int i; //int framecount = 0; //for (i = 0; i < 512; i++) { // framecount += get_byte(pb); //} AVFrame *pictFrame = avcodec_alloc_frame(); if (!pictFrame) return 0; uint8_t *pictBuffer = (uint8_t *)av_malloc(avpicture_get_size(STREAM_PIX_FMT, srcData.vd.pCodecCtx->width, srcData.vd.pCodecCtx->height)); if (!pictBuffer) return 0; avpicture_fill((AVPicture *)pictFrame, pictBuffer, STREAM_PIX_FMT, srcData.vd.pCodecCtx->width, srcData.vd.pCodecCtx->height); AVPacket srcPacket; AVPacket dstPacket; int frameNum = 0; int bytesRemaining = 0; int bytesDecoded = 0; int got_picture = 0; uint8_t *rawData = NULL; ReSampleContext *resample = NULL; int resamplebufferSize = 0; uint8_t * resamplepBuffer = NULL; uint8_t *saveBufferPtr = NULL; uint8_t *saveBuffer = NULL; int saveBufferSize = 0; int saveFrame = 0; if (useSound) { if (srcData.sd.pCodecCtx->channels != dstData.sd.pCodecCtx->channels || srcData.sd.pCodecCtx->sample_rate != dstData.sd.pCodecCtx->sample_rate) { resample = audio_resample_init( dstData.sd.pCodecCtx->channels, srcData.sd.pCodecCtx->channels, dstData.sd.pCodecCtx->sample_rate, srcData.sd.pCodecCtx->sample_rate); resamplebufferSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; resamplepBuffer = (uint8_t *)CC_malloc(resamplebufferSize); } saveBuffer = (uint8_t *)CC_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE*2); saveFrame = dstData.sd.pCodecCtx->frame_size * dstData.sd.pCodecCtx->channels * 2; } int current = 0; PourcentConvertion = 10.; bool _Aborted = false; while (!_Aborted && (rawData || av_read_frame(srcData.pFormatCtx, &srcPacket) >= 0)) { //PourcentConvertion = ((float)current / (float)framecount) * 100.0; if (srcPacket.stream_index == srcData.vd.streamIndex) { if (!rawData) { rawData = srcPacket.data; bytesRemaining = srcPacket.size; } got_picture = 0; bytesDecoded = avcodec_decode_video( srcData.vd.pCodecCtx, srcData.vd.pFrame, &got_picture, rawData, bytesRemaining); bytesRemaining -= bytesDecoded; if (bytesRemaining > 0) rawData += bytesDecoded; else rawData = NULL; if (got_picture) { error = img_convert((AVPicture *)pictFrame, STREAM_PIX_FMT, (AVPicture *)srcData.vd.pFrame, STREAM_PIX_FMT, srcData.vd.pCodecCtx->width, srcData.vd.pCodecCtx->height); int out_size = avcodec_encode_video(dstData.vd.pCodecCtx, dstData.vd.pBuffer, dstData.vd.bufferSize, pictFrame); /* if zero size, it means the image was buffered */ if (out_size > 0) { memset(&dstPacket, 0, sizeof(dstPacket)); av_init_packet(&dstPacket); //dstPacket.pts = av_rescale_q(dstData.vd.pCodecCtx->coded_frame->pts, dstData.pFormatCtx->streams[0]->codec->time_base, srcData.pFormatCtx->streams[0]->time_base); dstPacket.pts = av_rescale_q(dstData.vd.pCodecCtx->coded_frame->pts, dstData.pFormatCtx->streams[0]->codec->time_base, dstData.pFormatCtx->streams[0]->time_base); //dstPacket.pts = 0; if (!(frameNum % dstData.vd.pCodecCtx->gop_size)) dstPacket.flags |= PKT_FLAG_KEY; dstPacket.stream_index = 0; //video index dstPacket.data = dstData.vd.pBuffer; dstPacket.size = out_size; dstPacket.pos = -1; /* write the compressed frame in the media file */ error = av_interleaved_write_frame(dstData.pFormatCtx, &dstPacket); frameNum++; } } if (!rawData) av_free_packet(&srcPacket); } else if (useSound && srcPacket.stream_index == srcData.sd.streamIndex) { int frameSize = AVCODEC_MAX_AUDIO_FRAME_SIZE; if (resample) { avcodec_decode_audio2( srcData.sd.pCodecCtx, (int16_t *)resamplepBuffer, &frameSize, srcPacket.data, srcPacket.size); memset(srcData.sd.pBuffer, 0, AVCODEC_MAX_AUDIO_FRAME_SIZE); frameSize = audio_resample(resample,(int16_t *)srcData.sd.pBuffer, (int16_t *)resamplepBuffer, frameSize / (srcData.sd.pCodecCtx->channels * 2)); frameSize = frameSize * dstData.sd.pCodecCtx->channels * 2; } else { avcodec_decode_audio2( srcData.sd.pCodecCtx, (int16_t *)srcData.sd.pBuffer, &frameSize, srcPacket.data, srcPacket.size); } current ++; memcpy(saveBuffer + saveBufferSize, srcData.sd.pBuffer, frameSize); saveBufferPtr = saveBuffer; saveBufferSize += frameSize; while (saveBufferSize >= saveFrame) { memset(&dstPacket, 0, sizeof(dstPacket)); av_init_packet(&dstPacket); dstPacket.size = avcodec_encode_audio(dstData.sd.pCodecCtx, dstData.sd.pBuffer, saveFrame, (short *) saveBufferPtr); if (dstPacket.size > 0) { //dstPacket.flags |= PKT_FLAG_KEY; dstPacket.stream_index = 1; //audio index dstPacket.data = dstData.sd.pBuffer; dstPacket.pts = 0; error = av_interleaved_write_frame(dstData.pFormatCtx, &dstPacket); } av_free_packet(&srcPacket); saveBufferPtr += saveFrame; saveBufferSize -= saveFrame; } if (saveBufferPtr != saveBuffer) { for (int i=0; i