home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Geek 6
/
Geek-006.iso
/
linux
/
video
/
xmovie-1.5.3.tar.gz
/
xmovie-1.5.3.tar
/
xmovie-1.5.3
/
quicktime
/
yv12.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-11-29
|
12KB
|
391 lines
#include "colormodels.h"
#include "yv12.h"
#ifndef CLAMP
#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
#endif
static int quicktime_delete_codec_yv12(quicktime_video_map_t *vtrack)
{
quicktime_yv12_codec_t *codec;
codec = ((quicktime_codec_t*)vtrack->codec)->priv;
free(codec->work_buffer);
free(codec);
return 0;
}
static int quicktime_reads_colormodel_yv12(quicktime_t *file,
int colormodel,
int track)
{
return (colormodel == BC_RGB888 ||
colormodel == BC_YUV888 ||
colormodel == BC_YUV420P);
}
static int quicktime_writes_colormodel_yv12(quicktime_t *file,
int colormodel,
int track)
{
return (colormodel == BC_YUV420P);
}
static int quicktime_decode_yv12(quicktime_t *file, unsigned char **row_pointers, int track)
{
long bytes, x, y;
quicktime_video_map_t *vtrack = &(file->vtracks[track]);
quicktime_yv12_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
int width = vtrack->track->tkhd.track_width;
int height = vtrack->track->tkhd.track_height;
unsigned char *buffer;
unsigned char *output_row0, *output_row1, *y_plane0, *y_plane1, *u_plane, *v_plane;
long y_size, u_size, v_size;
int result = 0;
int y1, u, v, y2, r, g, b, y3, y4;
int bytes_per_row = width * cmodel_calculate_pixelsize(file->color_model);
y_size = codec->coded_h * codec->coded_w;
u_size = codec->coded_h * codec->coded_w / 4;
v_size = codec->coded_h * codec->coded_w / 4;
vtrack->track->tkhd.track_width;
quicktime_set_video_position(file, vtrack->current_position, track);
bytes = quicktime_frame_size(file, vtrack->current_position, track);
switch(file->color_model)
{
case BC_RGB888:
buffer = codec->work_buffer;
result = !quicktime_read_data(file, buffer, bytes);
for(y = 0; y < height; y += 2)
{
y_plane0 = codec->work_buffer + y * codec->coded_w;
y_plane1 = codec->work_buffer + (y + 1) * codec->coded_w;
u_plane = codec->work_buffer + y_size + y * codec->coded_w / 4;
v_plane = codec->work_buffer + y_size + u_size + y * codec->coded_w / 4;
output_row0 = row_pointers[y];
if(y + 1 < height) output_row1 = row_pointers[y + 1];
for(x = 0; x < width; x += 2)
{
y1 = *y_plane0++;
y1 <<= 16;
u = *u_plane++;
v = *v_plane++;
r = ((y1 + codec->yuv_table.vtor_tab[v]) >> 16);
g = ((y1 + codec->yuv_table.utog_tab[u] + codec->yuv_table.vtog_tab[v]) >> 16);
b = ((y1 + codec->yuv_table.utob_tab[u]) >> 16);
*output_row0++ = CLAMP(r, 0, 255);
*output_row0++ = CLAMP(g, 0, 255);
*output_row0++ = CLAMP(b, 0, 255);
if(y + 1 < height)
{
y1 = *y_plane1++;
y1 <<= 16;
r = ((y1 + codec->yuv_table.vtor_tab[v]) >> 16);
g = ((y1 + codec->yuv_table.utog_tab[u] + codec->yuv_table.vtog_tab[v]) >> 16);
b = ((y1 + codec->yuv_table.utob_tab[u]) >> 16);
*output_row1++ = CLAMP(r, 0, 255);
*output_row1++ = CLAMP(g, 0, 255);
*output_row1++ = CLAMP(b, 0, 255);
}
if(x + 1 < width)
{
y1 = *y_plane0++;
y1 <<= 16;
r = ((y1 + codec->yuv_table.vtor_tab[v]) >> 16);
g = ((y1 + codec->yuv_table.utog_tab[u] + codec->yuv_table.vtog_tab[v]) >> 16);
b = ((y1 + codec->yuv_table.utob_tab[u]) >> 16);
*output_row0++ = CLAMP(r, 0, 255);
*output_row0++ = CLAMP(g, 0, 255);
*output_row0++ = CLAMP(b, 0, 255);
}
if(y + 1 < height && x + 1 < width)
{
y1 = *y_plane1++;
y1 <<= 16;
r = ((y1 + codec->yuv_table.vtor_tab[v]) >> 16);
g = ((y1 + codec->yuv_table.utog_tab[u] + codec->yuv_table.vtog_tab[v]) >> 16);
b = ((y1 + codec->yuv_table.utob_tab[u]) >> 16);
*output_row1++ = CLAMP(r, 0, 255);
*output_row1++ = CLAMP(g, 0, 255);
*output_row1++ = CLAMP(b, 0, 255);
}
}
}
break;
case BC_YUV888:
buffer = codec->work_buffer;
result = !quicktime_read_data(file, buffer, bytes);
for(y = 0; y < height; y += 2)
{
y_plane0 = codec->work_buffer + y * codec->coded_w;
y_plane1 = codec->work_buffer + (y + 1) * codec->coded_w;
u_plane = codec->work_buffer + y_size + y * codec->coded_w / 4;
v_plane = codec->work_buffer + y_size + u_size + y * codec->coded_w / 4;
output_row0 = row_pointers[y];
if(y + 1 < height) output_row1 = row_pointers[y + 1];
for(x = 0; x < width; x += 2)
{
*output_row0++ = *y_plane0++;
*output_row0++ = u = *u_plane++;
*output_row0++ = v = *v_plane++;
if(y + 1 < height)
{
*output_row1++ = *y_plane1++;
*output_row1++ = u;
*output_row1++ = v;
}
if(x + 1 < height)
{
*output_row0++ = *y_plane0++;
*output_row0++ = u;
*output_row0++ = v;
}
if(x + 1 < height && y + 1 < height)
{
*output_row1++ = *y_plane1++;
*output_row1++ = u;
*output_row1++ = v;
}
}
}
break;
case BC_YUV420P:
result = !quicktime_read_data(file, row_pointers[0], y_size);
result = !quicktime_read_data(file, row_pointers[1], u_size);
result = !quicktime_read_data(file, row_pointers[2], v_size);
break;
}
return result;
}
static int quicktime_encode_yv12(quicktime_t *file, unsigned char **row_pointers, int track)
{
long offset = quicktime_position(file);
quicktime_video_map_t *vtrack = &(file->vtracks[track]);
quicktime_yv12_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
int result = 0;
int width = vtrack->track->tkhd.track_width;
int height = vtrack->track->tkhd.track_height;
long bytes;
unsigned char *y_plane0, *y_plane1, *u_plane, *v_plane;
long y_size, u_size, v_size;
unsigned char *input_row0, *input_row1;
int x, y;
int y1, u, y2, v, y3, y4, subscript;
int r, g, b;
y_size = codec->coded_h * codec->coded_w;
u_size = codec->coded_h * codec->coded_w / 4;
v_size = codec->coded_h * codec->coded_w / 4;
bytes = y_size + u_size + v_size;
switch(file->color_model)
{
case BC_RGB888:
for(y = 0; y < height; y += 2)
{
y_plane0 = codec->work_buffer + y * codec->coded_w;
y_plane1 = codec->work_buffer + (y + 1) * codec->coded_w;
u_plane = codec->work_buffer + y_size + y * codec->coded_w / 4;
v_plane = codec->work_buffer + y_size + u_size + y * codec->coded_w / 4;
input_row0 = row_pointers[y];
if(y + 1 < height) input_row1 = row_pointers[y + 1];
for(x = 0; x < width; x += 2)
{
r = *input_row0++;
g = *input_row0++;
b = *input_row0++;
y1 = (codec->yuv_table.rtoy_tab[r] +
codec->yuv_table.gtoy_tab[g] +
codec->yuv_table.btoy_tab[b]) >> 16;
u = (codec->yuv_table.rtou_tab[r] +
codec->yuv_table.gtou_tab[g] +
codec->yuv_table.btou_tab[b]);
v = (codec->yuv_table.rtov_tab[r] +
codec->yuv_table.gtov_tab[g] +
codec->yuv_table.btov_tab[b]);
subscript = 1;
if(y + 1 < height)
{
r = *input_row1++;
g = *input_row1++;
b = *input_row1++;
y2 = (codec->yuv_table.rtoy_tab[r] +
codec->yuv_table.gtoy_tab[g] +
codec->yuv_table.btoy_tab[b]) >> 16;
u += (codec->yuv_table.rtou_tab[r] +
codec->yuv_table.gtou_tab[g] +
codec->yuv_table.btou_tab[b]);
v += (codec->yuv_table.rtov_tab[r] +
codec->yuv_table.gtov_tab[g] +
codec->yuv_table.btov_tab[b]);
subscript++;
}
if(x + 1 < width)
{
r = *input_row0++;
g = *input_row0++;
b = *input_row0++;
y3 = (codec->yuv_table.rtoy_tab[r] +
codec->yuv_table.gtoy_tab[g] +
codec->yuv_table.btoy_tab[b]) >> 16;
u += (codec->yuv_table.rtou_tab[r] +
codec->yuv_table.gtou_tab[g] +
codec->yuv_table.btou_tab[b]);
v += (codec->yuv_table.rtov_tab[r] +
codec->yuv_table.gtov_tab[g] +
codec->yuv_table.btov_tab[b]);
subscript++;
}
if(x + 1 < width && y + 1 < height)
{
r = *input_row1++;
g = *input_row1++;
b = *input_row1++;
y4 = (codec->yuv_table.rtoy_tab[r] +
codec->yuv_table.gtoy_tab[g] +
codec->yuv_table.btoy_tab[b]) >> 16;
u += (codec->yuv_table.rtou_tab[r] +
codec->yuv_table.gtou_tab[g] +
codec->yuv_table.btou_tab[b]);
v += (codec->yuv_table.rtov_tab[r] +
codec->yuv_table.gtov_tab[g] +
codec->yuv_table.btov_tab[b]);
subscript++;
}
*y_plane0++ = CLAMP(y1, 0, 255);
*y_plane1++ = CLAMP(y2, 0, 255);
*y_plane0++ = CLAMP(y3, 0, 255);
*y_plane1++ = CLAMP(y4, 0, 255);
u /= subscript;
v /= subscript;
u >>= 16;
v >>= 16;
*u_plane++ = CLAMP(u, -128, 127) + 128;
*v_plane++ = CLAMP(v, -128, 127) + 128;
}
}
result = !quicktime_write_data(file, codec->work_buffer, bytes);
break;
case BC_YUV888:
for(y = 0; y < height; y += 2)
{
y_plane0 = codec->work_buffer + y * codec->coded_w;
y_plane1 = codec->work_buffer + (y + 1) * codec->coded_w;
u_plane = codec->work_buffer + y_size + y * codec->coded_w / 4;
v_plane = codec->work_buffer + y_size + u_size + y * codec->coded_w / 4;
input_row0 = row_pointers[y];
if(y + 1 < height) input_row1 = row_pointers[y + 1];
for(x = 0; x < width; x += 2)
{
*y_plane0++ = *input_row0++;
u = *input_row0++;
v = *input_row0++;
subscript = 1;
if(y + 1 < height)
{
*y_plane1++ = *input_row1++;
u += *input_row1++;
v += *input_row1++;
subscript++;
}
if(x + 1 < width)
{
*y_plane0++ = *input_row0++;
u += *input_row0++;
v += *input_row0++;
subscript++;
}
if(x + 1 < width && y + 1 < height)
{
*y_plane1++ = *input_row1++;
u += *input_row1++;
v += *input_row1++;
subscript++;
}
u /= subscript;
v /= subscript;
*u_plane++ = CLAMP(u, 0, 255);
*v_plane++ = CLAMP(v, 0, 255);
}
}
result = !quicktime_write_data(file, codec->work_buffer, bytes);
break;
case BC_YUV420P:
result = !quicktime_write_data(file, row_pointers[0], y_size);
result = !quicktime_write_data(file, row_pointers[1], u_size);
result = !quicktime_write_data(file, row_pointers[2], v_size);
break;
}
quicktime_update_tables(file,
file->vtracks[track].track,
offset,
file->vtracks[track].current_chunk,
file->vtracks[track].current_position,
1,
bytes);
file->vtracks[track].current_chunk++;
return result;
}
void quicktime_init_codec_yv12(quicktime_video_map_t *vtrack)
{
int i;
quicktime_yv12_codec_t *codec;
/* Init public items */
((quicktime_codec_t*)vtrack->codec)->priv = calloc(1, sizeof(quicktime_yv12_codec_t));
((quicktime_codec_t*)vtrack->codec)->delete_vcodec = quicktime_delete_codec_yv12;
((quicktime_codec_t*)vtrack->codec)->decode_video = quicktime_decode_yv12;
((quicktime_codec_t*)vtrack->codec)->encode_video = quicktime_encode_yv12;
((quicktime_codec_t*)vtrack->codec)->decode_audio = 0;
((quicktime_codec_t*)vtrack->codec)->encode_audio = 0;
((quicktime_codec_t*)vtrack->codec)->reads_colormodel = quicktime_reads_colormodel_yv12;
/* Init private items */
codec = ((quicktime_codec_t*)vtrack->codec)->priv;
codec->coded_w = (int)(vtrack->track->tkhd.track_width / 2);
codec->coded_w *= 2;
codec->coded_h = (int)(vtrack->track->tkhd.track_height / 2);
codec->coded_h *= 2;
cmodel_init_yuv(&codec->yuv_table);
codec->work_buffer = malloc(codec->coded_w * codec->coded_w + codec->coded_w * codec->coded_w / 2);
}