diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/demuxers/demux_flv.c | 232 | 
1 files changed, 160 insertions, 72 deletions
| diff --git a/src/demuxers/demux_flv.c b/src/demuxers/demux_flv.c index d319ece74..d3da20136 100644 --- a/src/demuxers/demux_flv.c +++ b/src/demuxers/demux_flv.c @@ -21,10 +21,10 @@  /*   * Flash Video (.flv) File Demuxer   *   by Mike Melanson (melanson@pcisys.net) and  - *      Claudio Ciccani (klan@directfb.org) + *      Claudio Ciccani (klan@users.sf.net)   *   * For more information on the FLV file format, visit: - * http://download.macromedia.com/pub/flash/flash_file_format_specification.pdf + * http://www.adobe.com/devnet/flv/pdf/video_file_format_spec_v9.pdf   */  #ifdef HAVE_CONFIG_H @@ -110,14 +110,20 @@ typedef struct {  #define FLV_SOUND_FORMAT_ADPCM   0x01  #define FLV_SOUND_FORMAT_MP3     0x02  #define FLV_SOUND_FORMAT_PCM_LE  0x03 +#define FLV_SOUND_FORMAT_NELLY16 0x04 /* Nellymoser 16KHz */  #define FLV_SOUND_FORMAT_NELLY8  0x05 /* Nellymoser 8KHz */  #define FLV_SOUND_FORMAT_NELLY   0x06 /* Nellymoser */ +#define FLV_SOUND_FORMAT_ALAW    0x07 /* G.711 A-LAW */ +#define FLV_SOUND_FORMAT_MULAW   0x08 /* G.711 MU-LAW */ +#define FLV_SOUND_FORMAT_AAC     0x0a +#define FLV_SOUND_FORMAT_MP38    0x0e /* MP3 8KHz */  #define FLV_VIDEO_FORMAT_FLV1    0x02 /* Sorenson H.263 */  #define FLV_VIDEO_FORMAT_SCREEN  0x03  #define FLV_VIDEO_FORMAT_VP6     0x04 /* On2 VP6 */  #define FLV_VIDEO_FORMAT_VP6A    0x05 /* On2 VP6 with alphachannel */  #define FLV_VIDEO_FORMAT_SCREEN2 0x06 +#define FLV_VIDEO_FORMAT_H264    0x07  #define FLV_DATA_TYPE_NUMBER     0x00  #define FLV_DATA_TYPE_BOOL       0x01 @@ -429,11 +435,24 @@ static int read_flv_packet(demux_flv_t *this, int preview) {              buf_type = BUF_AUDIO_FLVADPCM;              break;            case FLV_SOUND_FORMAT_MP3: +          case FLV_SOUND_FORMAT_MP38:              buf_type = BUF_AUDIO_MPEG;              break;            case FLV_SOUND_FORMAT_PCM_LE:              buf_type = BUF_AUDIO_LPCM_LE;              break; +          case FLV_SOUND_FORMAT_ALAW: +            buf_type = BUF_AUDIO_ALAW; +            break; +          case FLV_SOUND_FORMAT_MULAW: +            buf_type = BUF_AUDIO_MULAW; +            break; +          case FLV_SOUND_FORMAT_AAC: +            buf_type = BUF_AUDIO_AAC; +            /* AAC extra header */ +            this->input->read(this->input, buffer, 1 ); +            remaining_bytes--; +            break;            default:              lprintf("  unsupported audio format (%d)...\n", buffer[0] >> 4);              buf_type = BUF_AUDIO_UNKNOWN; @@ -464,8 +483,17 @@ static int read_flv_packet(demux_flv_t *this, int preview) {          }          remaining_bytes--; -        if ((buffer[0] >> 4) == 0x01) -          buf_flags = BUF_FLAG_KEYFRAME; +        switch ((buffer[0] >> 4)) { +          case 0x01: +            buf_flags = BUF_FLAG_KEYFRAME; +            break; +          case 0x05: +            /* skip server command */ +            this->input->seek(this->input, remaining_bytes, SEEK_CUR); +            continue; +          default: +            break; +        }          this->videocodec = buffer[0] & 0x0F; /* override */          switch (this->videocodec) { @@ -484,6 +512,12 @@ static int read_flv_packet(demux_flv_t *this, int preview) {              this->input->read(this->input, buffer, 4);              remaining_bytes -= 4;              break; +          case FLV_VIDEO_FORMAT_H264: +            buf_type = BUF_VIDEO_H264; +            /* AVC extra header */ +            this->input->read(this->input, buffer, 4); +            remaining_bytes -= 4; +            break;            default:              lprintf("  unsupported video format (%d)...\n", buffer[0] & 0x0F);              buf_type = BUF_VIDEO_UNKNOWN; @@ -511,6 +545,23 @@ static int read_flv_packet(demux_flv_t *this, int preview) {              bih->biSize++;              buf->size++;            } +          else if (buf_type == BUF_VIDEO_H264 && buffer[0] == 0) { +            /* AVC sequence header */ +            if (remaining_bytes > buf->max_size-buf->size) { +              xprintf(this->xine, XINE_VERBOSITY_LOG, +                    _("sequence header too big (%u bytes)!\n"), remaining_bytes); +              this->input->read(this->input, buf->content+buf->size, buf->max_size-buf->size); +              this->input->seek(this->input, remaining_bytes-buf->max_size-buf->size, SEEK_CUR); +              bih->biSize = buf->max_size; +              buf->size = buf->max_size; +            } +            else { +              this->input->read(this->input, buf->content+buf->size, remaining_bytes); +              bih->biSize += remaining_bytes; +              buf->size += remaining_bytes; +            } +            remaining_bytes = 0; +          }            fifo->put(fifo, buf);            this->got_video_header = 1;          } @@ -537,11 +588,21 @@ static int read_flv_packet(demux_flv_t *this, int preview) {                  buf->type = BUF_AUDIO_FLVADPCM;                  break;                case FLV_SOUND_FORMAT_MP3: +              case FLV_SOUND_FORMAT_MP38:                  buf->type = BUF_AUDIO_MPEG;                  break;                case FLV_SOUND_FORMAT_PCM_LE:                  buf->type = BUF_AUDIO_LPCM_LE;                  break; +              case FLV_SOUND_FORMAT_ALAW: +                buf->type = BUF_AUDIO_ALAW; +                break; +              case FLV_SOUND_FORMAT_MULAW: +                buf->type = BUF_AUDIO_MULAW; +                break; +              case FLV_SOUND_FORMAT_AAC: +                buf->type = BUF_AUDIO_AAC; +                break;                default:                  buf->type = BUF_AUDIO_UNKNOWN;                  break; @@ -549,9 +610,10 @@ static int read_flv_packet(demux_flv_t *this, int preview) {              buf->size = 0;              this->audio_fifo->put(this->audio_fifo, buf);              this->got_audio_header = 1; +            lprintf("  got audio header from metadata...\n");            } -          if (!this->got_video_header && this->videocodec) { +          if (!this->got_video_header && this->videocodec && this->videocodec != FLV_VIDEO_FORMAT_H264) {              xine_bmiheader *bih;              buf = this->video_fifo->buffer_pool_alloc(this->video_fifo);              buf->decoder_flags = BUF_FLAG_HEADER | BUF_FLAG_STDHEADER | @@ -583,6 +645,7 @@ static int read_flv_packet(demux_flv_t *this, int preview) {              }              this->video_fifo->put(this->video_fifo, buf);              this->got_video_header = 1; +            lprintf("  got video header from metadata...\n");            }            return this->status; @@ -600,33 +663,61 @@ static int read_flv_packet(demux_flv_t *this, int preview) {      while (remaining_bytes) {        buf = fifo->buffer_pool_alloc(fifo);        buf->type = buf_type; -      buf->pts = (int64_t) pts * 90; -       -      if (!preview) -        check_newpts(this, buf->pts, (tag_type == FLV_TAG_TYPE_VIDEO));        buf->extra_info->input_time = pts;        if (this->input->get_length(this->input)) {          buf->extra_info->input_normpos =               (int)((double)this->input->get_current_pos(this->input) * 65535.0 / this->size);        } +       +      if ((buf_type == BUF_VIDEO_H264 || buf_type == BUF_AUDIO_AAC) && buffer[0] == 0) { +        /* AVC/AAC sequence header */ +        buf->pts = 0; +        buf->size = 0; +         +        buf->decoder_flags = BUF_FLAG_SPECIAL | BUF_FLAG_HEADER; +        if (preview) +          buf->decoder_flags |= BUF_FLAG_PREVIEW; -      if (remaining_bytes > buf->max_size) -        buf->size = buf->max_size; -      else -        buf->size = remaining_bytes; -      remaining_bytes -= buf->size; - -      buf->decoder_flags = buf_flags; -      if (preview) -        buf->decoder_flags |= BUF_FLAG_PREVIEW; -      if (!remaining_bytes) -        buf->decoder_flags |= BUF_FLAG_FRAME_END; - -      if (this->input->read(this->input, buf->content, buf->size) != buf->size) { -        buf->free_buffer(buf); -        this->status = DEMUX_FINISHED; -        break; +        buf->decoder_info[1] = BUF_SPECIAL_DECODER_CONFIG; +        buf->decoder_info[2] = MIN(remaining_bytes, buf->max_size); +        buf->decoder_info_ptr[2] = buf->mem; +       +        if (this->input->read(this->input, buf->mem, buf->decoder_info[2]) != buf->decoder_info[2]) { +          buf->free_buffer(buf); +          this->status = DEMUX_FINISHED; +          break; +        } +         +        if (remaining_bytes > buf->max_size) { +          xprintf(this->xine, XINE_VERBOSITY_LOG, +                _("sequence header too big (%u bytes)!\n"), remaining_bytes); +          this->input->seek(this->input, remaining_bytes-buf->max_size, SEEK_CUR); +        } +        remaining_bytes = 0; +      } +      else { +        buf->pts = (int64_t) pts * 90; +        if (!preview) +          check_newpts(this, buf->pts, (tag_type == FLV_TAG_TYPE_VIDEO)); + +        if (remaining_bytes > buf->max_size) +          buf->size = buf->max_size; +        else +          buf->size = remaining_bytes; +        remaining_bytes -= buf->size; + +        buf->decoder_flags = buf_flags; +        if (preview) +          buf->decoder_flags |= BUF_FLAG_PREVIEW; +        if (!remaining_bytes) +          buf->decoder_flags |= BUF_FLAG_FRAME_END; + +        if (this->input->read(this->input, buf->content, buf->size) != buf->size) { +          buf->free_buffer(buf); +          this->status = DEMUX_FINISHED; +          break; +        }        }        fifo->put(fifo, buf); @@ -649,8 +740,8 @@ static void seek_flv_file(demux_flv_t *this, off_t seek_pos, int seek_pts) {    lprintf("  seeking %s to %d...\n",             do_rewind ? "backward" : "forward", seek_pts); -      -  if (seek_pts == 0) { +   +  if (seek_pos == 0 && seek_pts == 0) {      this->input->seek(this->input, this->start, SEEK_SET);      this->cur_pts = 0;      return; @@ -676,11 +767,9 @@ static void seek_flv_file(demux_flv_t *this, off_t seek_pos, int seek_pts) {        this->input->seek(this->input, this->index[i].offset-4, SEEK_SET);        this->cur_pts = this->index[i].pts; -      return;      }    } -   -  if (seek_pos && this->videocodec && abs(seek_pts-this->cur_pts) > 300000) { +  else if (seek_pos && this->videocodec && abs(seek_pts-this->cur_pts) > 300000) {      off_t pos, size;      pos = this->input->get_current_pos(this->input); @@ -715,49 +804,50 @@ static void seek_flv_file(demux_flv_t *this, off_t seek_pos, int seek_pts) {      lprintf("  ...resync failed!\n");      this->input->seek(this->input, pos, SEEK_SET); -    return;    }   -   -  while (do_rewind ? (seek_pts < this->cur_pts) : (seek_pts > this->cur_pts)) { -    unsigned char tag_type; -    int           data_size; -    int           ptag_size; +  else if (seek_pts) {  +    while (do_rewind ? (seek_pts < this->cur_pts) : (seek_pts > this->cur_pts)) { +      unsigned char tag_type; +      int           data_size; +      int           ptag_size; -    if (next_tag) -      this->input->seek(this->input, next_tag, SEEK_CUR); +      if (next_tag) +        this->input->seek(this->input, next_tag, SEEK_CUR); -    len = this->input->read(this->input, buffer, 16); -    if (len != 16) { -      len = (len < 0) ? 0 : len; -      break; -    } +      len = this->input->read(this->input, buffer, 16); +      if (len != 16) { +        len = (len < 0) ? 0 : len; +        break; +      } -    ptag_size = _X_BE_32(&buffer[0]); -    tag_type = buffer[4]; -    data_size = _X_BE_24(&buffer[5]); -    pts = _X_BE_24(&buffer[8]) | (buffer[11] << 24); +      ptag_size = _X_BE_32(&buffer[0]); +      tag_type = buffer[4]; +      data_size = _X_BE_24(&buffer[5]); +      pts = _X_BE_24(&buffer[8]) | (buffer[11] << 24); -    if (do_rewind) { -      if (!ptag_size) break; /* beginning of movie */ -      next_tag = -(ptag_size + 16 + 4); -    } -    else { -      next_tag = data_size - 1; -    } +      if (do_rewind) { +        if (!ptag_size) +          break; /* beginning of movie */ +        next_tag = -(ptag_size + 16 + 4); +      } +      else { +        next_tag = data_size - 1; +      } -    if (this->flags & FLV_FLAG_HAS_VIDEO) { -      /* sync to video key frame */ -      if (tag_type != FLV_TAG_TYPE_VIDEO || (buffer[15] >> 4) != 0x01) -        continue; -      lprintf("  video keyframe found at %d...\n", pts); +      if (this->flags & FLV_FLAG_HAS_VIDEO) { +        /* sync to video key frame */ +        if (tag_type != FLV_TAG_TYPE_VIDEO || (buffer[15] >> 4) != 0x01) +          continue; +        lprintf("  video keyframe found at %d...\n", pts); +      } +      this->cur_pts = pts;      } -    this->cur_pts = pts; -  } -  /* seek back to the beginning of the tag */ -  this->input->seek(this->input, -len, SEEK_CUR); +    /* seek back to the beginning of the tag */ +    this->input->seek(this->input, -len, SEEK_CUR); -  lprintf( "  seeked to %d.\n", pts); +    lprintf( "  seeked to %d.\n", pts); +  }  } @@ -807,8 +897,12 @@ static int demux_flv_seek (demux_plugin_t *this_gen,    this->status = DEMUX_OK;    if (INPUT_IS_SEEKABLE(this->input)) { -    if (start_pos && !start_time) -      start_time = (int64_t) this->length * start_pos / 65535; +    if (start_pos && !start_time) { +      if (this->length)  +        start_time = (int64_t) this->length * start_pos / 65535; +      else if (this->index) +        start_time = this->index[(int)(start_pos * (this->num_indices-1) / 65535)].pts; +    }      if (!this->length || start_time < this->length) {        seek_flv_file(this, start_pos, start_time); @@ -875,12 +969,6 @@ static demux_plugin_t *open_plugin (demux_class_t *class_gen, xine_stream_t *str    switch (stream->content_detection_method) {      case METHOD_BY_EXTENSION: -      if (!_x_demux_check_extension(input->get_mrl(input), "flv")) { -        free (this); -        return NULL; -      } -   -  /* falling through is intended */        case METHOD_BY_CONTENT:      case METHOD_EXPLICIT:        if (!open_flv_file(this)) { | 
