JD2022-TU1/main/extern/Camcam/LIBS/ENCDEC/AVIToFLV.cpp

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