📄 spudec.cpp
字号:
height = (end_row < start_row) ? 0 : end_row - start_row /* + 1 */;
DPRINTF(_l("Coords col: %d - %d row: %d - %d (%dx%d)"), start_col, end_col, start_row, end_row, width, height);
off+=6;
break;
case 0x06:
/* Graphic lines */
current_nibble[0] = 2 * get_be16(this->packet + off);
current_nibble[1] = 2 * get_be16(this->packet + off + 2);
DPRINTF(_l("Graphic offset 1: %d offset 2: %d"), current_nibble[0] / 2, current_nibble[1] / 2);
off+=4;
break;
case 0xff:
/* All done, bye-bye */
DPRINTF(_l("Done!"));
return;
// break;
default:
DPRINTF(_l("spudec: Error determining control type 0x%02x. Skipping %d bytes."), type, next_off - off);
goto next_control;
}
}
next_control:
if (display) {
packet_t *packet = (packet_t*)calloc(1, sizeof(packet_t));
int i;
packet->start_pts = start_pts;
if (end_pts == UINT_MAX && start_off != next_off) {
start_pts = pts100 + get_be16(this->packet + next_off) * 1024;
packet->end_pts = start_pts - 1;
} else packet->end_pts = end_pts;
packet->current_nibble[0] = current_nibble[0];
packet->current_nibble[1] = current_nibble[1];
packet->start_row = start_row;
packet->end_row = end_row;
packet->start_col = start_col;
packet->end_col = end_col;
packet->width = width;
packet->height = height;
packet->stride = stride;
packet->control_start = control_start;
for (i=0; i<4; i++) {
packet->alpha[i] = this->alpha[i];
packet->palette[i] = this->palette[i];
}
packet->packet = (unsigned char*)malloc(this->packet_size);
memcpy(packet->packet, this->packet, this->packet_size);
spudec_queue_packet(packet);
}
}
}
void Tspudec::spudec_decode(unsigned int pts100)
{
spudec_process_control( pts100);
}
int Tspudec::spudec_changed(void)
{
return (spu_changed || now_pts > end_pts);
}
void Tspudec::spudec_assemble(const unsigned char *packet, unsigned int len, unsigned int pts100)
{
if (len < 2) {
DPRINTF(_l("SPUasm: packet too short"));
return;
}
if ((this->packet_pts + 10000) < pts100) {
// [cb] too long since last fragment: force new packet
this->packet_offset = 0;
}
this->packet_pts = pts100;
if (this->packet_offset == 0) {
unsigned int len2 = get_be16(packet);
// Start new fragment
if (this->packet_reserve < len2) {
if (this->packet != NULL)
free(this->packet);
this->packet = (unsigned char*)malloc(len2);
this->packet_reserve = this->packet != NULL ? len2 : 0;
}
if (this->packet != NULL) {
this->packet_size = len2;
if (len > len2) {
DPRINTF(_l("SPUasm: invalid frag len / len2: %d / %d "), len, len2);
return;
}
memcpy(this->packet, packet, len);
this->packet_offset = len;
this->packet_pts = pts100;
}
} else {
// Continue current fragment
if (this->packet_size < this->packet_offset + len){
DPRINTF(_l("SPUasm: invalid fragment"));
this->packet_size = this->packet_offset = 0;
return;
} else {
memcpy(this->packet + this->packet_offset, packet, len);
this->packet_offset += len;
}
}
#if 1
// check if we have a complete packet (unfortunately packet_size is bad
// for some disks)
// [cb] packet_size is padded to be even -> may be one byte too long
if ((this->packet_offset == this->packet_size) ||
((this->packet_offset + 1) == this->packet_size)){
unsigned int x=0,y;
while(x+4<=this->packet_offset){
y=get_be16(this->packet+x+2); // next control pointer
DPRINTF(_l("SPUtest: x=%d y=%d off=%d size=%d"),x,y,this->packet_offset,this->packet_size);
if(x>=4 && x==y){ // if it points to self - we're done!
// we got it!
DPRINTF(_l("SPUgot: off=%d size=%d "),this->packet_offset,this->packet_size);
spudec_decode(pts100);
this->packet_offset = 0;
break;
}
if(y<=x || y>=this->packet_size){ // invalid?
DPRINTF(_l("SPUtest: broken packet!!!!! y=%d < x=%d"),y,x);
this->packet_size = this->packet_offset = 0;
break;
}
x=y;
}
// [cb] packet is done; start new packet
this->packet_offset = 0;
}
#else
if (this->packet_offset == this->packet_size) {
spudec_decode(pts100);
this->packet_offset = 0;
}
#endif
/*
packet_t *p=queue_head;
while (p)
{
DPRINTF("packet: %i %i",p->start_pts,p->end_pts);
p=p->next;
}*/
}
void Tspudec::spudec_reset(void) // called after seek
{
while (queue_head)
spudec_free_packet(spudec_dequeue_packet());
now_pts = 0;
end_pts = 0;
packet_size = packet_offset = 0;
}
void Tspudec::spudec_heartbeat(unsigned int pts100)
{
now_pts = pts100;
while (queue_head != NULL && pts100 >= queue_head->start_pts) {
packet_t *packet = spudec_dequeue_packet();
start_pts = packet->start_pts;
end_pts = packet->end_pts;
if (auto_palette)
compute_palette( packet);
spudec_process_data( packet);
spudec_free_packet(packet);
spu_changed = 1;
}
}
int Tspudec::spudec_visible(void){
int ret=(start_pts <= now_pts &&
now_pts < end_pts &&
height > 0);
// printf("spu visible: %d ",ret);
return ret;
}
void Tspudec::spudec_set_forced_subs_only( const unsigned int flag)
{
forced_subs_only=flag;
DPRINTF(_l("SPU: Display only forced subs now %s"), flag ? _l("enabled"): _l("disabled"));
}
/*
void Tspudec::spudec_draw( void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride,const void *self),const void *self)
{
if (start_pts <= now_pts && now_pts < end_pts && image)
{
draw_alpha(start_col, start_row, width, height,
image, aimage, stride,self);
spu_changed = 0;
}
}
*/
/* calc the bbox for spudec subs */
void Tspudec::spudec_calc_bbox( unsigned int dxs, unsigned int dys, unsigned int* bbox)
{
int y1;
if (orig_frame_width == 0 || orig_frame_height == 0
|| (orig_frame_width == dxs && orig_frame_height == dys)) {
bbox[0] = start_col;
bbox[1] = start_col + width;
bbox[2] = start_row;
bbox[3] = start_row + height;
}
else if (scaled_frame_width != dxs || scaled_frame_height != dys) {
unsigned int scalex = 0x100 * dxs / orig_frame_width;
unsigned int scaley = 0x100 * dys / orig_frame_height;
bbox[0] = start_col * scalex / 0x100;
bbox[1] = start_col * scalex / 0x100 + width * scalex / 0x100;
switch (spu_alignment) {
case 0:
bbox[3] = dys*sub_pos/100 + height * scaley / 0x100;
if (bbox[3] > dys) bbox[3] = dys;
bbox[2] = bbox[3] - height * scaley / 0x100;
break;
case 1:
if (sub_pos < 50) {
y1 = dys*sub_pos/100 - height * scaley / 0x200;
if (y1 < 0) bbox[2] = 0; else bbox[2] = y1;
bbox[3] = bbox[2] + height;
} else {
bbox[3] = dys*sub_pos/100 + height * scaley / 0x200;
if (bbox[3] > dys) bbox[3] = dys;
bbox[2] = bbox[3] - height * scaley / 0x100;
}
break;
case 2:
y1 = dys*sub_pos/100 - height * scaley / 0x100;
if (y1 < 0) bbox[2] = 0; else bbox[2] = y1;
bbox[3] = bbox[2] + height;
break;
default: /* -1 */
bbox[2] = start_row * scaley / 0x100;
bbox[3] = start_row * scaley / 0x100 + height * scaley / 0x100;
break;
}
}
}
/* transform mplayer's alpha value into an opacity value that is linear */
int Tspudec::canon_alpha(int alpha)
{
return alpha ? 256 - alpha : 0;
}
void Tspudec::scale_table(unsigned int start_src, unsigned int start_tar, unsigned int end_src, unsigned int end_tar, scale_pixel * table)
{
unsigned int t;
unsigned int delta_src = end_src - start_src;
unsigned int delta_tar = end_tar - start_tar;
int src = 0;
int src_step;
if (delta_src == 0 || delta_tar == 0) {
return;
}
src_step = (delta_src << 16) / delta_tar >>1;
for (t = 0; t<=delta_tar; src += (src_step << 1), t++){
table[t].position= std::min((unsigned int)(src >> 16), end_src - 1);
table[t].right_down = src & 0xffff;
table[t].left_up = 0x10000 - table[t].right_down;
}
}
/* bilinear scale, similar to vobsub's code */
void Tspudec::scale_image(int x, int y, scale_pixel* table_x, scale_pixel* table_y)
{
int alpha[4];
int color[4];
unsigned int scale[4];
int base = table_y[y].position * stride + table_x[x].position;
int scaled = y * scaled_strideY + x;
alpha[0] = canon_alpha(aimage[base]);
alpha[1] = canon_alpha(aimage[base + 1]);
alpha[2] = canon_alpha(aimage[base + stride]);
alpha[3] = canon_alpha(aimage[base + stride + 1]);
color[0] = image[base];
color[1] = image[base + 1];
color[2] = image[base + stride];
color[3] = image[base + stride + 1];
scale[0] = (table_x[x].left_up * table_y[y].left_up >> 16) * alpha[0];
scale[1] = (table_x[x].right_down * table_y[y].left_up >>16) * alpha[1];
scale[2] = (table_x[x].left_up * table_y[y].right_down >> 16) * alpha[2];
scale[3] = (table_x[x].right_down * table_y[y].right_down >> 16) * alpha[3];
scaled_imageY[scaled] = (unsigned char)((color[0] * scale[0] + color[1] * scale[1] + color[2] * scale[2] + color[3] * scale[3])>>24);
scaled_aimageY[scaled] = (unsigned char)((scale[0] + scale[1] + scale[2] + scale[3]) >> 16);
/*
if (scaled_aimage[scaled]){
scaled_aimage[scaled] = (unsigned char)(256 - scaled_aimage[scaled]);
if(scaled_aimage[scaled] + scaled_image[scaled] > 255)
scaled_image[scaled] = (unsigned char)(256 - scaled_aimage[scaled]);
}*/
}
void Tspudec::sws_spu_image(unsigned char *d1, unsigned char *d2, int dw, int dh, stride_t ds,
unsigned char *s1, unsigned char *s2, int sw, int sh, stride_t ss,const TrenderedSubtitleLines::TprintPrefs &prefs)
{
if (!filter.lumH || oldgauss != prefs.vobaagauss)
{
if (filter.lumH) libmplayer->sws_freeVec(filter.lumH);
filter.lumH = filter.lumV = filter.chrH = filter.chrV = libmplayer->sws_getGaussianVec(prefs.vobaagauss/1000.0, 3.0);
libmplayer->sws_normalizeVec(filter.lumH, 1.0);
oldgauss = prefs.vobaagauss;
}
SwsParams params;Tlibmplayer::swsInitParams(¶ms,SWS_GAUSS);
SwsContext *ctx=libmplayer->sws_getContext(sw, sh, IMGFMT_Y800, dw, dh, IMGFMT_Y800, ¶ms, &filter, NULL);
libmplayer->sws_scale_ordered(ctx,(const uint8_t**)&s1,&ss,0,sh,&d1,&ds);
for (stride_t i=ss*sh-1; i>=0; i--) s2[i]=(unsigned char)canon_alpha(s2[i]);
libmplayer->sws_scale_ordered(ctx,(const uint8_t**)&s2,&ss,0,sh,&d2,&ds);
libmplayer->sws_freeContext(ctx);
}
void Tspudec::spudec_draw_scaled(unsigned int dxs, unsigned int dys, TdrawAlpha draw_alpha,const TrenderedSubtitleLines::TprintPrefs &prefs)
{
scale_pixel *table_x;
scale_pixel *table_y;
int y1;
if (start_pts <= now_pts && now_pts < end_pts) {
// check if only forced subtitles are requested
if( (forced_subs_only) && !(is_forced_sub) ){
return;
}
/*
if (!(spu_aamode&16) && (orig_frame_width == 0 || orig_frame_height == 0
|| (orig_frame_width == dxs && orig_frame_height == dys))) {
if (image)
{
draw_alpha(start_col, start_row, width, height,
imageY, aimageY, strideY, imageUV, aimageUV,strideUV self);
spu_changed = 0;
}
}
else*/ {
if (/*oldscale!=prefs.vobscale || */scaled_frame_width != dxs || scaled_frame_height != dys || spu_aamode!=prefs.vobaamode) { /* Resizing is needed */
spu_aamode=prefs.vobaamode;
oldscale=prefs.vobscale;
/* scaled_x = scalex * x / 0x100
scaled_y = scaley * y / 0x100
order of operations is important because of rounding. */
unsigned int scalex = prefs.vobscale * dxs / orig_frame_width;
unsigned int scaley = prefs.vobscale * dys / orig_frame_height;
scaled_start_col = start_col * scalex / 0x100;
scaled_start_row = start_row * scaley / 0x100;
scaled_width = width * scalex / 0x100;
scaled_height = height * scaley / 0x100;
/* Kludge: draw_alpha needs width multiple of 8 */
scaled_strideY = (scaled_width + 7) & ~7;
scaled_strideUV = ((scaled_width/2) + 7) & ~7;
if (scaled_image_size < scaled_strideY * scaled_height) {
if (scaled_imageY) {
free(scaled_imageY);
scaled_image_size = 0;
}
if (scaled_imageUV)
free(scaled_imageUV);
scaled_imageY = (unsigned char*) malloc(2 * scaled_strideY * scaled_height);
scaled_imageUV= (unsigned char*) malloc(2 * scaled_strideUV* ((scaled_height+1)/2));
if (scaled_imageY) {
scaled_image_size = scaled_strideY * scaled_height;
scaled_aimageY = scaled_imageY + scaled_image_size;
scaled_aimageUV= scaled_imageUV+ scaled_strideUV * ((scaled_height+1)/2);
}
}
if (scaled_imageY) {
//unsigned int x, y;
/* Kludge: draw_alpha needs width multiple of 8. */
if (scaled_width < scaled_strideY)
for (unsigned int y = 0; y < scaled_height; ++y)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -