⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spudec.cpp

📁 从FFMPEG转换而来的H264解码程序,VC下编译..
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/* 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;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -