?? spudec.cpp
字號(hào):
/* SPUdec.c
Skeleton of function spudec_process_controll() is from xine sources.
Further works:
LGB,... (yeah, try to improve it and insert your name here! ;-)
Kim Minh Kaplan
implement fragments reassembly, RLE decoding.
read brightness from the IFO.
For information on SPU format see <URL:http://sam.zoy.org/doc/dvd/subtitles/>
and <URL:http://members.aol.com/mpucoder/DVD/spu.html>
*/
// to ffdshow imported from mplayer
#include "stdafx.h"
#include "ffImgfmt.h"
#include "spudec.h"
#include "postproc/swscale.h"
#include "Tlibmplayer.h"
#include "IffdshowBase.h"
#include "ffdshow_constants.h"
#include "Tconfig.h"
#include "ffdebug.h"
/* Valid values for spu_aamode:
0: none (fastest, most ugly)
1: approximate
2: full (slowest)
3: bilinear (similiar to vobsub, fast and not too bad)
4: uses swscaler gaussian (this is the only one that looks good)
*/
/*
Tspudec::Tspudec(IffdshowBase *Ideci):deci(Ideci)
{
spu_aamode = 3;
spu_alignment = -1;
spu_gaussvar = 1.0;
sub_pos=0;
firsttime=1;
}
*/
void Tspudec::spudec_queue_packet( packet_t *packet)
{
if (queue_head == NULL)
queue_head = packet;
else
queue_tail->next = packet;
queue_tail = packet;
}
Tspudec::packet_t* Tspudec::spudec_dequeue_packet()
{
packet_t *retval = queue_head;
queue_head = retval->next;
if (queue_head == NULL)
queue_tail = NULL;
return retval;
}
void Tspudec::spudec_free_packet(packet_t *packet)
{
if (packet->packet != NULL)
free(packet->packet);
free(packet);
}
unsigned int Tspudec::get_be16(const unsigned char *p)
{
return (p[0] << 8) + p[1];
}
unsigned int Tspudec::get_be24(const unsigned char *p)
{
return (get_be16(p) << 8) + p[2];
}
void Tspudec::next_line(packet_t *packet)
{
if (packet->current_nibble[packet->deinterlace_oddness] % 2)
packet->current_nibble[packet->deinterlace_oddness]++;
packet->deinterlace_oddness = (packet->deinterlace_oddness + 1) % 2;
}
unsigned char Tspudec::get_nibble(packet_t *packet)
{
unsigned char nib;
unsigned int *nibblep = packet->current_nibble + packet->deinterlace_oddness;
if (*nibblep / 2 >= packet->control_start) {
DPRINTF( _l("SPUdec: ERROR: get_nibble past end of packet"));
return 0;
}
nib = packet->packet[*nibblep / 2];
if (*nibblep % 2)
nib &= 0xf;
else
nib >>= 4;
++*nibblep;
return nib;
}
/* Cut the sub to visible part */
void Tspudec::spudec_cut_image(void)
{
unsigned int fy, ly;
unsigned int first_y, last_y;
unsigned char *image;
unsigned char *aimage;
if (this->stride == 0 || this->height == 0) {
return;
}
for (fy = 0; fy < this->image_size && !this->aimage[fy]; fy++);
for (ly = this->stride * this->height-1; ly && !this->aimage[ly]; ly--);
first_y = fy / this->stride;
last_y = ly / this->stride;
//printf("first_y: %d, last_y: %d", first_y, last_y);
this->start_row += first_y;
// Some subtitles trigger this condition
if (last_y + 1 > first_y ) {
this->height = last_y - first_y +1;
} else {
this->height = 0;
this->image_size = 0;
return;
}
// printf("new h %d new start %d (sz %d st %d)---\n", this->height, this->start_row, this->image_size, this->stride);
image = (unsigned char*)malloc(2 * this->stride * this->height);
if(image){
this->image_size = this->stride * this->height;
aimage = image + this->image_size;
memcpy(image, this->image + this->stride * first_y, this->image_size);
memcpy(aimage, this->aimage + this->stride * first_y, this->image_size);
free(this->image);
this->image = image;
this->aimage = aimage;
} else {
DPRINTF(_l("Fatal: update_spu: malloc requested %d bytes"), 2 * this->stride * this->height);
}
}
int Tspudec::mkalpha(int i)
{
/* In mplayer's alpha planes, 0 is transparent, then 1 is nearly
opaque upto 255 which is transparent */
switch (i) {
case 0xf:
return 1;
case 0:
return 0;
default:
return (0xf - i) << 4;
}
}
void Tspudec::spudec_process_data( packet_t *packet)
{
unsigned int cmap[4], alpha[4];
unsigned int i, x, y;
this->scaled_frame_width = 0;
this->scaled_frame_height = 0;
this->start_col = packet->start_col;
this->end_col = packet->end_col;
this->start_row = packet->start_row;
this->end_row = packet->end_row;
this->height = packet->height;
this->width = packet->width;
this->stride = packet->stride;
for (i = 0; i < 4; ++i) {
alpha[i] = mkalpha(packet->alpha[i]);
if (alpha[i] == 0)
cmap[i] = 0;
else if (this->custom){
cmap[i] = this->cuspal[i].Y;
if (cmap[i] + alpha[i] > 255)
cmap[i] = 256 - alpha[i];
}
else {
cmap[i] = this->global_palette[packet->palette[i]].Y;
if (cmap[i] + alpha[i] > 255)
cmap[i] = 256 - alpha[i];
}
}
if (this->image_size < this->stride * this->height) {
if (this->image != NULL) {
free(this->image);
this->image_size = 0;
}
this->image = (unsigned char*)malloc(2 * this->stride * this->height);
if (this->image) {
this->image_size = this->stride * this->height;
this->aimage = this->image + this->image_size;
}
}
if (this->image == NULL)
return;
/* Kludge: draw_alpha needs width multiple of 8. */
if (this->width < this->stride)
for (y = 0; y < this->height; ++y) {
memset(this->aimage + y * this->stride + this->width, 0, this->stride - this->width);
/* FIXME: Why is this one needed? */
memset(this->image + y * this->stride + this->width, 0, this->stride - this->width);
}
i = packet->current_nibble[1];
x = 0;
y = 0;
while (packet->current_nibble[0] < i
&& packet->current_nibble[1] / 2 < packet->control_start
&& y < this->height) {
unsigned int len, color;
unsigned int rle = 0;
rle = get_nibble(packet);
if (rle < 0x04) {
rle = (rle << 4) | get_nibble(packet);
if (rle < 0x10) {
rle = (rle << 4) | get_nibble(packet);
if (rle < 0x040) {
rle = (rle << 4) | get_nibble(packet);
if (rle < 0x0004)
rle |= ((this->width - x) << 2);
}
}
}
color = 3 - (rle & 0x3);
len = rle >> 2;
if (len > this->width - x || len == 0)
len = this->width - x;
/* FIXME have to use palette and alpha map*/
memset(this->image + y * this->stride + x, cmap[color], len);
memset(this->aimage + y * this->stride + x, alpha[color], len);
x += len;
if (x >= this->width) {
next_line(packet);
x = 0;
++y;
}
}
spudec_cut_image();
}
/*
This function tries to create a usable palette.
It determines how many non-transparent colors are used, and assigns different
gray scale values to each color.
I tested it with four streams and even got something readable. Half of the
times I got black characters with white around and half the reverse.
*/
void Tspudec::compute_palette(packet_t *packet)
{
int used[16],i,cused,start,step,color;
memset(used, 0, sizeof(used));
for (i=0; i<4; i++)
if (packet->alpha[i]) /* !Transparent? */
used[packet->palette[i]] = 1;
for (cused=0, i=0; i<16; i++)
if (used[i]) cused++;
if (!cused) return;
if (cused == 1) {
start = 0x80;
step = 0;
} else {
start = font_start_level;
step = (0xF0-font_start_level)/(cused-1);
}
memset(used, 0, sizeof(used));
for (i=0; i<4; i++) {
color = packet->palette[i];
if (packet->alpha[i] && !used[color]) { /* not assigned? */
used[color] = 1;
global_palette[color].Y = UCHAR(start);
start += step;
}
}
}
void Tspudec::spudec_process_control( unsigned int pts100)
{
int a,b; /* Temporary vars */
unsigned int date, type;
unsigned int off;
unsigned int start_off = 0;
unsigned int next_off;
unsigned int start_pts=0;
unsigned int end_pts=0;
unsigned int current_nibble[2];
unsigned int control_start;
unsigned int display = 0;
unsigned int start_col = 0;
unsigned int end_col = 0;
unsigned int start_row = 0;
unsigned int end_row = 0;
unsigned int width = 0;
unsigned int height = 0;
unsigned int stride = 0;
control_start = get_be16(this->packet + 2);
next_off = control_start;
while (start_off != next_off) {
start_off = next_off;
date = get_be16(this->packet + start_off) * 1024;
next_off = get_be16(this->packet + start_off + 2);
DPRINTF( _l("date=%d"), date);
off = start_off + 4;
for (type = this->packet[off++]; type != 0xff; type = this->packet[off++]) {
DPRINTF( _l("cmd=%d "),type);
switch(type) {
case 0x00:
/* Menu ID, 1 byte */
DPRINTF(_l("Menu ID"));
/* shouldn't a Menu ID type force display start? */
start_pts = pts100 + date;
end_pts = UINT_MAX;
display = 1;
this->is_forced_sub=(unsigned int)~0; // current subtitle is forced
break;
case 0x01:
/* Start display */
start_pts = pts100 + date;
end_pts = UINT_MAX;
display = 1;
DPRINTF(_l("Start display! %i"),start_pts);
this->is_forced_sub=0;
break;
case 0x02:
/* Stop display */
end_pts = pts100 + date;
DPRINTF(_l("Stop display! %i"),end_pts);
break;
case 0x03:
/* Palette */
this->palette[0] = this->packet[off] >> 4;
this->palette[1] = this->packet[off] & 0xf;
this->palette[2] = this->packet[off + 1] >> 4;
this->palette[3] = this->packet[off + 1] & 0xf;
DPRINTF(_l("Palette %d, %d, %d, %d"), this->palette[0], this->palette[1], this->palette[2], this->palette[3]);
off+=2;
break;
case 0x04:
/* Alpha */
this->alpha[0] = this->packet[off] >> 4;
this->alpha[1] = this->packet[off] & 0xf;
this->alpha[2] = this->packet[off + 1] >> 4;
this->alpha[3] = this->packet[off + 1] & 0xf;
DPRINTF(_l("Alpha %d, %d, %d, %d"), this->alpha[0], this->alpha[1], this->alpha[2], this->alpha[3]);
off+=2;
break;
case 0x05:
/* Co-ords */
a = get_be24(this->packet + off);
b = get_be24(this->packet + off + 3);
start_col = a >> 12;
end_col = a & 0xfff;
width = (end_col < start_col) ? 0 : end_col - start_col + 1;
stride = (width + 7) & ~7; /* Kludge: draw_alpha needs width multiple of 8 */
start_row = b >> 12;
end_row = b & 0xfff;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -