mpv/libvo/vo_odivx.c

235 lines
4.7 KiB
C

/*
* OpenDivX AVI file writer
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "video_out.h"
#include "video_out_internal.h"
LIBVO_EXTERN(odivx)
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "../encore/encore.h"
static vo_info_t vo_info =
{
"OpenDivX AVI File writer",
"odivx",
"Arpad Gereoffy <arpi@esp-team.scene.hu>",
""
};
static uint8_t *image=NULL;
static int image_width=0;
static int image_height=0;
static unsigned int image_format=0;
static char *buffer=NULL;
static int frameno=0;
extern char* encode_name;
extern char* encode_index_name;
//static uint32_t draw_slice(uint8_t *src[], uint32_t slice_num)
static uint32_t draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y)
{
uint8_t *s;
uint8_t *d;
int i;
int dstride=image_width;
// copy Y
d=image+dstride*y+x;
s=src[0];
for(i=0;i<h;i++){
memcpy(d,s,w);
s+=stride[0];
d+=dstride;
}
w/=2;h/=2;x/=2;y/=2; dstride/=2;
// copy U
d=image+image_width*image_height + dstride*y+x;
s=src[1];
for(i=0;i<h;i++){
memcpy(d,s,w);
s+=stride[1];
d+=dstride;
}
// copy V
d=image+image_width*image_height +image_width*image_height/4 + dstride*y+x;
s=src[2];
for(i=0;i<h;i++){
memcpy(d,s,w);
s+=stride[2];
d+=dstride;
}
return 0;
}
static uint32_t
draw_frame(uint8_t *src[])
{
uint8_t *d=image;
switch(image_format){
case IMGFMT_YV12:
// copy Y
memcpy(d,src[0],image_width*image_height);
// copy U
d+=image_width*image_height;
memcpy(d,src[1],image_width*image_height/4);
// copy V
d+=image_width*image_height/4;
memcpy(d,src[2],image_width*image_height/4);
break;
// case IMGFMT_YUY2:
case IMGFMT_BGR|24:
memcpy(d,src[0],image_width*image_height*3);
break;
}
return 0;
}
typedef unsigned int DWORD;
typedef struct
{
DWORD ckid;
DWORD dwFlags;
DWORD dwChunkOffset; // Position of chunk
DWORD dwChunkLength; // Length of chunk
} AVIINDEXENTRY;
static void
flip_page(void)
{
// we are rady to encode this frame
ENC_FRAME enc_frame;
ENC_RESULT enc_result;
if(++frameno<10) return;
enc_frame.bmp=image;
enc_frame.bitstream=buffer;
enc_frame.length=0;
encore(0x123,0,&enc_frame,&enc_result);
printf("coded length: %d \n",enc_frame.length);
if(encode_name){
AVIINDEXENTRY i;
FILE *file;
i.ckid=('c'<<24)|('d'<<16)|('0'<<8)|'0'; // "00dc"
i.dwFlags=enc_result.isKeyFrame?0x10:0;
i.dwChunkLength=enc_frame.length;
// Write AVI chunk:
if((file=fopen(encode_name,"ab"))){
unsigned char zerobyte=0;
i.dwChunkOffset=ftell(file);
fwrite(&i.ckid,4,1,file);
fwrite(&enc_frame.length,4,1,file);
fwrite(buffer,enc_frame.length,1,file);
if(enc_frame.length&1) fwrite(&zerobyte,1,1,file); // padding
fclose(file);
}
// Write AVI index:
if(encode_index_name && (file=fopen(encode_index_name,"ab"))){
fwrite(&i,sizeof(i),1,file);
fclose(file);
}
}
}
static uint32_t
query_format(uint32_t format)
{
switch(format){
case IMGFMT_YV12:
// case IMGFMT_YUY2:
case IMGFMT_BGR|24:
return 1;
}
return 0;
}
extern int encode_bitrate;
static uint32_t
init(uint32_t width, uint32_t height, uint32_t d_width, uint32_t d_height, uint32_t fullscreen, char *title, uint32_t format)
{
uint32_t frame_size;
ENC_PARAM enc_param;
// file = fopen("encoded.odvx","wb");
// if(!file) return -1;
switch(format){
case IMGFMT_YV12:
frame_size=width*height+width*height/2;
enc_param.flip=2; // 0=RGB 1=flippedRGB 2=planarYUV format
break;
case IMGFMT_BGR|24:
enc_param.flip=0; // 0=RGB 1=flippedRGB 2=planarYUV format
frame_size=width*height*3;
break;
default: return -1; // invalid format
}
enc_param.x_dim=width;
enc_param.y_dim=height;
image_width=width;
image_height=height;
image_format=format;
image=malloc(frame_size);
//clear the buffer
memset(image,0x80,frame_size);
// buffer for encoded video data:
buffer=malloc(0x100000);
if(!buffer) return -1;
// encoding parameters:
enc_param.framerate=25.0;
enc_param.bitrate=encode_bitrate?encode_bitrate:780000;
enc_param.rc_period=300;
enc_param.max_quantizer=15;
enc_param.min_quantizer=1;
enc_param.search_range=128;
// init codec:
encore(0x123,ENC_OPT_INIT,&enc_param,NULL);
return 0;
}
static const vo_info_t*
get_info(void)
{
return &vo_info;
}
static void
uninit(void)
{
}