432 lines
12 KiB
C++
432 lines
12 KiB
C++
#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; i<data->pFormatCtx->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; i<data->pFormatCtx->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<saveBufferSize; i++)
|
|
saveBuffer[i] = saveBufferPtr[i];
|
|
}
|
|
} else
|
|
av_free_packet(&srcPacket);
|
|
|
|
(Aborted == NULL) ? _Aborted = false : _Aborted = *Aborted;
|
|
Sleep(1);
|
|
}
|
|
|
|
if (saveBuffer)
|
|
CC_free(saveBuffer);
|
|
|
|
if (resample)
|
|
audio_resample_close(resample);
|
|
if (resamplepBuffer)
|
|
CC_free(resamplepBuffer);
|
|
|
|
FreeAVIData(&srcData, 0);
|
|
FreeAVIData(&dstData, 1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
#else
|
|
|
|
int AVIToFlv(char *src, char *dst)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|