452 lines
11 KiB
C++
452 lines
11 KiB
C++
#include "SCENE.h"
|
|
|
|
#ifdef VIDEO_OPENLIB
|
|
|
|
#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 WORLD *TheScene;
|
|
|
|
extern "C" {
|
|
#include "libavformat/avformat.h"
|
|
#include "libavutil/avutil.h"
|
|
#include "libavcodec/avcodec.h"
|
|
}
|
|
|
|
//#define COPY_CASH
|
|
|
|
#define MAX_DELAY_TIME 60
|
|
|
|
#define V_ENCDEC_CODEC CODEC_ID_MPEG4 //CODEC_ID_H263 CODEC_ID_FLV1
|
|
#define STREAM_FRAME_RATE 25 /* 25 images/s */
|
|
#define STREAM_PIX_FMT PIX_FMT_YUV420P
|
|
#define PICTURE_PIX_FMT PIX_FMT_RGB32
|
|
|
|
#define A_ENCDEC_CODEC CODEC_ID_MP3 //CODEC_ID_MP2 //
|
|
|
|
static AVCodec *vCodecEnc = NULL;
|
|
static AVCodec *vCodecDec = NULL;
|
|
|
|
static AVCodec *aCodecEnc = NULL;
|
|
static AVCodec *aCodecDec = NULL;
|
|
|
|
typedef struct _VideoData
|
|
{
|
|
AVCodecContext *c;
|
|
AVFrame *pict;
|
|
AVFrame *noBufferPict;
|
|
} VideoData;
|
|
|
|
|
|
typedef struct _AudioData
|
|
{
|
|
AVCodecContext *c;
|
|
int head;
|
|
int sampleSize;
|
|
uint8_t *inBuffer;
|
|
} AudioData;
|
|
|
|
|
|
typedef struct _AVData
|
|
{
|
|
VideoData *vd;
|
|
AudioData *sd;
|
|
} AVData;
|
|
|
|
|
|
int AVCodec_Init()
|
|
{
|
|
av_register_all();
|
|
|
|
if (!vCodecEnc)
|
|
vCodecEnc = avcodec_find_encoder(V_ENCDEC_CODEC);
|
|
if (!vCodecDec)
|
|
vCodecDec = avcodec_find_decoder(V_ENCDEC_CODEC);
|
|
|
|
if (!aCodecEnc)
|
|
aCodecEnc = avcodec_find_encoder(A_ENCDEC_CODEC);
|
|
if (!aCodecDec)
|
|
aCodecDec = avcodec_find_decoder(A_ENCDEC_CODEC);
|
|
|
|
return vCodecEnc && vCodecDec && aCodecEnc && aCodecDec;
|
|
}
|
|
|
|
void *AVCodec_INIT(MAP *PPicture, bool encode)
|
|
{
|
|
AVData *data = (AVData *)CC_malloc(sizeof(VideoData));
|
|
VideoData *vd;
|
|
AudioData *sd;
|
|
AVCodec *codec;
|
|
|
|
if (encode)
|
|
codec = vCodecEnc;
|
|
else
|
|
codec = vCodecDec;
|
|
|
|
|
|
vd = data->vd = (VideoData *)CC_malloc(sizeof(VideoData));
|
|
memset(vd, 0, sizeof(VideoData));
|
|
vd->c = (AVCodecContext *) avcodec_alloc_context();
|
|
vd->c->codec_type = CODEC_TYPE_VIDEO;
|
|
vd->c->codec_id = vCodecDec->id;
|
|
|
|
/* put sample parameters */
|
|
vd->c->bit_rate = 10000;
|
|
vd->c->me_method = 1;
|
|
|
|
/* resolution must be a multiple of two */
|
|
vd->c->width = PPicture->SX;
|
|
vd->c->height = PPicture->SY;
|
|
|
|
/* 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. */
|
|
vd->c->time_base.den = STREAM_FRAME_RATE;
|
|
vd->c->time_base.num = 1;
|
|
vd->c->gop_size = 256; /* emit one intra frame every 256 frames at most */
|
|
vd->c->pix_fmt = STREAM_PIX_FMT;
|
|
|
|
/* Special case */
|
|
if (vd->c->codec_id == CODEC_ID_MPEG2VIDEO)
|
|
vd->c->max_b_frames = 2;
|
|
if (vd->c->codec_id == CODEC_ID_MPEG1VIDEO)
|
|
vd->c->mb_decision = 2;
|
|
|
|
if (avcodec_open(vd->c, codec) < 0)
|
|
return NULL;
|
|
|
|
int size;
|
|
uint8_t *picture_buf;
|
|
|
|
vd->pict = avcodec_alloc_frame();
|
|
vd->noBufferPict= avcodec_alloc_frame();
|
|
|
|
if (!vd->pict || !vd->noBufferPict)
|
|
return NULL;
|
|
|
|
size = avpicture_get_size(STREAM_PIX_FMT, PPicture->SX, PPicture->SY);
|
|
picture_buf = (uint8_t *)av_malloc(size);
|
|
|
|
if (!picture_buf)
|
|
{
|
|
av_free(vd->pict);
|
|
av_free(vd->noBufferPict);
|
|
return NULL;
|
|
}
|
|
avpicture_fill((AVPicture *)vd->pict, picture_buf, STREAM_PIX_FMT, PPicture->SX, PPicture->SY);
|
|
|
|
|
|
|
|
if (encode)
|
|
codec = aCodecEnc;
|
|
else
|
|
codec = aCodecDec;
|
|
|
|
sd = data->sd = (AudioData *)CC_malloc(sizeof(AudioData));
|
|
memset(sd, 0, sizeof(AudioData));
|
|
sd->c = (AVCodecContext *) avcodec_alloc_context();
|
|
sd->c->codec_id = codec->id;
|
|
sd->c->codec_type = CODEC_TYPE_AUDIO;
|
|
sd->c->bit_rate = SND_BIT_RATE;
|
|
sd->c->sample_rate = SND_SAMPLES;
|
|
sd->c->channels = SND_NB_CHANNELS;
|
|
|
|
if (avcodec_open(sd->c, codec) < 0)
|
|
return NULL;
|
|
|
|
if (encode)
|
|
{
|
|
sd->sampleSize = sd->c->frame_size*2*sd->c->channels;
|
|
sd->inBuffer = (uint8_t *)CC_malloc(data->sd->sampleSize);
|
|
sd->head = MicroInAddHead(&TheScene->microIn);
|
|
} else
|
|
{
|
|
sd->sampleSize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
|
|
sd->inBuffer = (uint8_t *)CC_malloc(data->sd->sampleSize);
|
|
}
|
|
|
|
MicroOutInit(&TheScene->microOut);
|
|
return data;
|
|
}
|
|
|
|
void AVCodec_CLOSE(void *H)
|
|
{
|
|
if (H)
|
|
{
|
|
AVData *data = (AVData *)H;
|
|
|
|
av_free(data->vd->c);
|
|
av_free(data->vd->pict);
|
|
av_free(data->vd->noBufferPict);
|
|
CC_free(data->vd);
|
|
|
|
MicroInDelHead(&TheScene->microIn, data->sd->head, 1);
|
|
av_free(data->sd->c);
|
|
CC_free(data->sd->inBuffer);
|
|
CC_free(data->sd);
|
|
|
|
CC_free(data);
|
|
}
|
|
}
|
|
|
|
|
|
void *AVCodec_Encode_INIT(MAP *PPicture)
|
|
{
|
|
if (!AVCodec_Init())
|
|
return NULL;
|
|
return AVCodec_INIT(PPicture, true);
|
|
}
|
|
|
|
u32 AVCodec_Encode_FRAME(void *H, MAP *PPicture, char *Buffer, u32 FROMSCRATCH)
|
|
{
|
|
int encodedSize;
|
|
AVData *data = (AVData *)H;
|
|
|
|
if (!H) return 0;
|
|
|
|
avpicture_fill((AVPicture *)data->vd->noBufferPict, (uint8_t *)PPicture->GetBase(), PICTURE_PIX_FMT, PPicture->SX, PPicture->SY);
|
|
encodedSize = img_convert( (AVPicture *)data->vd->pict, STREAM_PIX_FMT,
|
|
(AVPicture *)data->vd->noBufferPict, PICTURE_PIX_FMT, PPicture->SX, PPicture->SY);
|
|
|
|
if (FROMSCRATCH)
|
|
{
|
|
data->vd->pict->pict_type = FF_I_TYPE;
|
|
data->vd->pict->key_frame = 1;
|
|
//data->vd->pict->key_frame = 1;
|
|
} else
|
|
{
|
|
data->vd->pict->pict_type = FF_P_TYPE;
|
|
data->vd->pict->key_frame = 0;
|
|
}
|
|
|
|
encodedSize = avcodec_encode_video(data->vd->c, (uint8_t *)Buffer, DATA_MAX, data->vd->pict);
|
|
return encodedSize;
|
|
}
|
|
|
|
u32 AVCodec_Encode_AUDIO(void *H, char *Buffer)
|
|
{
|
|
AVData *data = (AVData *)H;
|
|
int encodedSize = 0;
|
|
char *BufferPtr = Buffer;
|
|
int bufferSize = DATA_MAX_SOUND;
|
|
|
|
if (!H) return 0;
|
|
|
|
#ifdef COPY_CASH
|
|
encodedSize = MicroInReadMax(&TheScene->microIn, data->sd->head,
|
|
(char *)Buffer , DATA_MAX_SOUND);
|
|
bufferSize -= encodedSize;
|
|
#else
|
|
while ( bufferSize > 0 &&
|
|
MicroInReadExactly( &TheScene->microIn, data->sd->head,
|
|
(char *)data->sd->inBuffer,data->sd->sampleSize))
|
|
{
|
|
//MicroOutWrite(&TheScene->microOut, (char *)data->sd->inBuffer, data->sd->sampleSize);
|
|
int encSize = avcodec_encode_audio(data->sd->c, (uint8_t *)BufferPtr, bufferSize, (short *) data->sd->inBuffer);
|
|
encodedSize += encSize;
|
|
BufferPtr += encSize;
|
|
bufferSize -= encSize;
|
|
}
|
|
#endif
|
|
if (bufferSize <= 0 || MicroInGetBufferedTime(&TheScene->microIn, data->sd->head) > MAX_DELAY_TIME)
|
|
MicroInFlush(&TheScene->microIn, data->sd->head);
|
|
|
|
return encodedSize;
|
|
}
|
|
|
|
|
|
|
|
void AVCodec_Encode_CLOSE(void *H)
|
|
{
|
|
AVCodec_CLOSE(H);
|
|
}
|
|
|
|
|
|
void *AVCodec_Decode_INIT(MAP *PPicture)
|
|
{
|
|
if (!AVCodec_Init())
|
|
return NULL;
|
|
return AVCodec_INIT(PPicture, false);
|
|
}
|
|
|
|
u32 AVCodec_Decode_FRAME(void *H, MAP *PPicture, char *Buffer, u32 BufferSize)
|
|
{
|
|
int got_picture = 0;
|
|
int encodedSize;
|
|
AVData *data = (AVData *)H;
|
|
|
|
if (!data || !BufferSize)
|
|
return 0;
|
|
|
|
encodedSize = avcodec_decode_video(data->vd->c, data->vd->pict, &got_picture, (uint8_t *)Buffer, BufferSize);
|
|
if (!got_picture || encodedSize <= 0)
|
|
return 0;
|
|
avpicture_fill((AVPicture *)data->vd->noBufferPict, (uint8_t *)PPicture->GetBase(), PICTURE_PIX_FMT, PPicture->SX, PPicture->SY);
|
|
encodedSize = img_convert( (AVPicture *)data->vd->noBufferPict, PICTURE_PIX_FMT,
|
|
(AVPicture *)data->vd->pict, STREAM_PIX_FMT, PPicture->SX, PPicture->SY);
|
|
return encodedSize;
|
|
}
|
|
|
|
|
|
|
|
u32 AVCodec_Decode_AUDIO(void *H, char *Buffer, int size)
|
|
{
|
|
AVData *data = (AVData *)H;
|
|
int encodedSize = 0;
|
|
int encodedFrameSize = 0;
|
|
char *BufferPtr = Buffer;
|
|
|
|
if (!H) return 0;
|
|
|
|
// FROMSCRATCH NOT IMPLEMENTED YET !!
|
|
//if (MicroOutGetBufferedTime(&TheScene->microOut) > MAX_DELAY_TIME)
|
|
// MicroOutFlush(&TheScene->microOut);
|
|
|
|
#ifdef COPY_CASH
|
|
MicroOutWrite(&TheScene->microOut, Buffer, size);
|
|
#else
|
|
while (size > 0)
|
|
{
|
|
encodedSize = data->sd->sampleSize;
|
|
encodedFrameSize= avcodec_decode_audio2(data->sd->c, (int16_t *)data->sd->inBuffer,
|
|
&encodedSize, (uint8_t *)Buffer, size);
|
|
if (encodedFrameSize > 0)
|
|
{
|
|
Buffer += encodedFrameSize;
|
|
size -= encodedFrameSize;
|
|
MicroOutWrite(&TheScene->microOut, (char *)data->sd->inBuffer, encodedSize);
|
|
}
|
|
else
|
|
size = 0;
|
|
}
|
|
#endif
|
|
return encodedSize;
|
|
}
|
|
|
|
|
|
void AVCodec_Decode_CLOSE(void *H)
|
|
{
|
|
AVCodec_CLOSE(H);
|
|
}
|
|
|
|
|
|
void *Encode_INIT(MAP *PPicture)
|
|
{
|
|
return AVCodec_Encode_INIT(PPicture);
|
|
}
|
|
|
|
u32 Encode_FRAME(void *H, MAP *PPicture, char *Buffer, u32 FROMSCRATCH, u32 Q, u32 R)
|
|
{
|
|
return AVCodec_Encode_FRAME(H, PPicture, Buffer, FROMSCRATCH);
|
|
}
|
|
|
|
void Encode_CLOSE(void *H)
|
|
{
|
|
AVCodec_Encode_CLOSE(H);
|
|
}
|
|
|
|
void *Decode_INIT(MAP *PPicture)
|
|
{
|
|
return AVCodec_Decode_INIT(PPicture);
|
|
}
|
|
|
|
u32 Decode_FRAME(void *H, MAP *PPicture, char *Buffer, u32 FROMSCRATCH)
|
|
{
|
|
return AVCodec_Decode_FRAME(H, PPicture, Buffer, FROMSCRATCH);
|
|
}
|
|
|
|
void Decode_CLOSE(void *H)
|
|
{
|
|
AVCodec_Decode_CLOSE(H);
|
|
}
|
|
|
|
|
|
|
|
//*************************************************
|
|
//*************************************************
|
|
|
|
|
|
u32 Timer = 0;
|
|
|
|
typedef struct Multiplexer_
|
|
{
|
|
u32 Identityfier;
|
|
u32 SoundSize;
|
|
u32 VideoSize;
|
|
u32 UserSize;
|
|
} Multiplexer;
|
|
|
|
#define ENCODE_SOUND
|
|
|
|
u32 Encode_FRAME_AND_SOUND(void *H, MAP *PPicture, char *DataBuffer, u32 FROMSCRATCH, u32 Q, u32 R)
|
|
{
|
|
#ifdef ENCODE_SOUND
|
|
static u32 LastTime = 0;
|
|
|
|
Multiplexer *pHeader;
|
|
pHeader = (Multiplexer *)DataBuffer;
|
|
pHeader ->Identityfier = 'SOUN';
|
|
DataBuffer += sizeof(Multiplexer);//*/
|
|
/* Encode Video ********************************************************************/
|
|
pHeader->VideoSize = Encode_FRAME(H, PPicture, DataBuffer, FROMSCRATCH, Q, R);
|
|
DataBuffer += pHeader->VideoSize;
|
|
/* Encode Sound ********************************************************************/
|
|
pHeader->SoundSize = AVCodec_Encode_AUDIO(H, DataBuffer);
|
|
return sizeof(Multiplexer) + pHeader->SoundSize + pHeader->VideoSize;
|
|
#else
|
|
return Encode_FRAME(H, PPicture, DataBuffer, FROMSCRATCH, Q, R) ;
|
|
#endif
|
|
}
|
|
|
|
u32 Decode_FRAME_AND_SOUND(void *H, MAP *PPicture, char *DataBuffer, u32 FROMSCRATCH)
|
|
{
|
|
#ifdef ENCODE_SOUND
|
|
Multiplexer *pHeader;
|
|
pHeader = (Multiplexer *)DataBuffer;
|
|
DataBuffer += sizeof(Multiplexer);//*/
|
|
if (pHeader ->Identityfier == 'SOUN')
|
|
{
|
|
u32 OKValue;
|
|
/* Decode Video ********************************************************************/
|
|
OKValue = Decode_FRAME(H, PPicture, DataBuffer, pHeader->VideoSize) ;
|
|
DataBuffer += pHeader->VideoSize;//*/
|
|
/* Decode Video ********************************************************************/
|
|
if (pHeader->SoundSize) AVCodec_Decode_AUDIO(H, DataBuffer, pHeader->SoundSize);
|
|
return OKValue;
|
|
}
|
|
else return -1;
|
|
#else
|
|
return Decode_FRAME(H, PPicture, DataBuffer, FROMSCRATCH) ;//*/
|
|
#endif
|
|
}
|
|
|
|
#else
|
|
|
|
void * Encode_INIT(MAP *)
|
|
{
|
|
return NULL;
|
|
}
|
|
u32 Encode_FRAME(void *, MAP *, char *, u32, u32 Q, u32 R)
|
|
{
|
|
return 0;
|
|
}
|
|
void Encode_CLOSE(void *)
|
|
{
|
|
}
|
|
|
|
void * Decode_INIT(MAP *)
|
|
{
|
|
return NULL;
|
|
}
|
|
u32 Decode_FRAME(void *, MAP *, char *, u32)
|
|
{
|
|
return 0;
|
|
}
|
|
void Decode_CLOSE(void *)
|
|
{
|
|
}
|
|
|
|
#endif
|