demux_audio.c

来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 796 行 · 第 1/2 页

C
796
字号
#include "config.h"#include "mp_msg.h"#include "help_mp.h"#include <mplaylib.h>#include <mplaylib.h>#include "stream/stream.h"#include "demuxer.h"#include "stheader.h"#include "genres.h"#include "mp3_hdr.h"#include "libavutil/intreadwrite.h"#include <mplaylib.h>#undef memcpy#define memcpy uc_memcpy#define MP3 1#define WAV 2#define fLaC 3#define HDR_SIZE 4typedef struct da_priv {  int frmt;  double next_pts;} da_priv_t;//! rather arbitrary value for maximum length of wav-format headers#define MAX_WAVHDR_LEN (1 * 1024 * 1024)//! how many valid frames in a row we need before accepting as valid MP3#define MIN_MP3_HDRS 12//! Used to describe a potential (chain of) MP3 headers we foundtypedef struct mp3_hdr {  off_t frame_pos; // start of first frame in this "chain" of headers  off_t next_frame_pos; // here we expect the next header with same parameters  int mp3_chans;  int mp3_freq;  int mpa_spf;  int mpa_layer;  int mpa_br;  int cons_hdrs; // if this reaches MIN_MP3_HDRS we accept as MP3 file  struct mp3_hdr *next;} mp3_hdr_t;extern void print_wave_header(WAVEFORMATEX *h, int verbose_level);int hr_mp3_seek = 1;static float mp3_totaltime = 0;/** * \brief free a list of MP3 header descriptions * \param list pointer to the head-of-list pointer */static void free_mp3_hdrs(mp3_hdr_t **list) {  mp3_hdr_t *tmp;  while (*list) {    tmp = (*list)->next;    free(*list);    *list = tmp;  }}/** * \brief add another potential MP3 header to our list * If it fits into an existing chain this one is expanded otherwise * a new one is created. * All entries that expected a MP3 header before the current position * are discarded. * The list is expected to be and will be kept sorted by next_frame_pos * and when those are equal by frame_pos. * \param list pointer to the head-of-list pointer * \param st_pos stream position where the described header starts * \param mp3_chans number of channels as specified by the header (*) * \param mp3_freq sampling frequency as specified by the header (*) * \param mpa_spf frame size as specified by the header * \param mpa_layer layer type ("version") as specified by the header (*) * \param mpa_br bitrate as specified by the header * \param mp3_flen length of the frame as specified by the header * \return If non-null the current file is accepted as MP3 and the * mp3_hdr struct describing the valid chain is returned. Must be * freed independent of the list. * * parameters marked by (*) must be the same for all headers in the same chain */static mp3_hdr_t *add_mp3_hdr(mp3_hdr_t **list, off_t st_pos,                               int mp3_chans, int mp3_freq, int mpa_spf,                               int mpa_layer, int mpa_br, int mp3_flen) {  mp3_hdr_t *tmp;  int in_list = 0;  while (*list && (*list)->next_frame_pos <= st_pos) {    if (((*list)->next_frame_pos < st_pos) || ((*list)->mp3_chans != mp3_chans)         || ((*list)->mp3_freq != mp3_freq) || ((*list)->mpa_layer != mpa_layer) ) {      // wasn't valid!      tmp = (*list)->next;      free(*list);      *list = tmp;    } else {      (*list)->cons_hdrs++;      (*list)->next_frame_pos = st_pos + mp3_flen;      (*list)->mpa_spf = mpa_spf;      (*list)->mpa_br = mpa_br;      if ((*list)->cons_hdrs >= MIN_MP3_HDRS) {        // copy the valid entry, so that the list can be easily freed        tmp = malloc(sizeof(mp3_hdr_t));        memcpy(tmp, *list, sizeof(mp3_hdr_t));        tmp->next = NULL;        return tmp;      }      in_list = 1;      list = &((*list)->next);    }  }  if (!in_list) { // does not belong into an existing chain, insert    // find right position to insert to keep sorting    while (*list && (*list)->next_frame_pos <= st_pos + mp3_flen)      list = &((*list)->next);    tmp = malloc(sizeof(mp3_hdr_t));    tmp->frame_pos = st_pos;    tmp->next_frame_pos = st_pos + mp3_flen;    tmp->mp3_chans = mp3_chans;    tmp->mp3_freq = mp3_freq;    tmp->mpa_spf = mpa_spf;    tmp->mpa_layer = mpa_layer;    tmp->mpa_br = mpa_br;    tmp->cons_hdrs = 1;    tmp->next = *list;    *list = tmp;  }  return NULL;}#define FLAC_SIGNATURE_SIZE 4#define FLAC_STREAMINFO_SIZE 34#define FLAC_SEEKPOINT_SIZE 18enum {  FLAC_STREAMINFO = 0,  FLAC_PADDING,  FLAC_APPLICATION,  FLAC_SEEKTABLE,  FLAC_VORBIS_COMMENT,  FLAC_CUESHEET} flac_preamble_t;static voidget_flac_metadata (demuxer_t* demuxer){  uint8_t preamble[4];  unsigned int blk_len;  stream_t *s = NULL;  if (!demuxer)    return;  s = demuxer->stream;  if (!s)    return;    /* file is qualified; skip over the signature bytes in the stream */  stream_seek (s, 4);  /* loop through the metadata blocks; use a do-while construct since there   * will always be 1 metadata block */  do {    int r;        r = stream_read (s, (char *) preamble, FLAC_SIGNATURE_SIZE);    if (r != FLAC_SIGNATURE_SIZE)      return;    blk_len = (preamble[1] << 16) | (preamble[2] << 8) | (preamble[3] << 0);    switch (preamble[0] & 0x7F)    {    case FLAC_STREAMINFO:    {      if (blk_len != FLAC_STREAMINFO_SIZE)        return;      stream_skip (s, FLAC_STREAMINFO_SIZE);      break;    }    case FLAC_PADDING:      stream_skip (s, blk_len);      break;    case FLAC_APPLICATION:      stream_skip (s, blk_len);      break;    case FLAC_SEEKTABLE:    {      int seekpoint_count, i;      seekpoint_count = blk_len / FLAC_SEEKPOINT_SIZE;      for (i = 0; i < seekpoint_count; i++)        if (stream_skip (s, FLAC_SEEKPOINT_SIZE) != 1)          return;      break;    }    case FLAC_VORBIS_COMMENT:    {      /* For a description of the format please have a look at */      /* http://www.xiph.org/vorbis/doc/v-comment.html */      uint32_t length, comment_list_len;      char comments[blk_len];      uint8_t *ptr = comments;      char *comment;      int cn;      char c;      if (stream_read (s, comments, blk_len) == blk_len)      {        length = AV_RL32(ptr);        ptr += 4 + length;        comment_list_len = AV_RL32(ptr);        ptr += 4;        cn = 0;        for (; cn < comment_list_len; cn++)        {          length = AV_RL32(ptr);          ptr += 4;          comment = ptr;          c = comment[length];          comment[length] = 0;          if (!strncasecmp ("TITLE=", comment, 6) && (length - 6 > 0))            demux_info_add (demuxer, "Title", comment + 6);          else if (!strncasecmp ("ARTIST=", comment, 7) && (length - 7 > 0))            demux_info_add (demuxer, "Artist", comment + 7);          else if (!strncasecmp ("ALBUM=", comment, 6) && (length - 6 > 0))            demux_info_add (demuxer, "Album", comment + 6);          else if (!strncasecmp ("DATE=", comment, 5) && (length - 5 > 0))            demux_info_add (demuxer, "Year", comment + 5);          else if (!strncasecmp ("GENRE=", comment, 6) && (length - 6 > 0))            demux_info_add (demuxer, "Genre", comment + 6);          else if (!strncasecmp ("Comment=", comment, 8) && (length - 8 > 0))            demux_info_add (demuxer, "Comment", comment + 8);          else if (!strncasecmp ("TRACKNUMBER=", comment, 12)                   && (length - 12 > 0))          {            char buf[31];            buf[30] = '\0';            sprintf (buf, "%d", atoi (comment + 12));            demux_info_add(demuxer, "Track", buf);          }          comment[length] = c;          ptr += length;        }      }      break;    }    case FLAC_CUESHEET:      stream_skip (s, blk_len);      break;    default:       /* 6-127 are presently reserved */      stream_skip (s, blk_len);      break;    }  } while ((preamble[0] & 0x80) == 0);}static uint32_t mp3_total_framecount(demuxer_t* demuxer){	uint8_t hdr[4];  int len;  int count = 0;  uint32_t pos_start;  int mp3_freq, mp3_chans, mp3_flen, mpa_layer, mpa_spf, mpa_br;  stream_t* s = demuxer->stream;  pos_start = stream_tell(s);  while(s->eof == 0) {    stream_read(demuxer->stream,hdr,4);    if (s->eof)    {    	 break;    }    len = mp_get_mp3_header(hdr, &mp3_chans, &mp3_freq,                                &mpa_spf, &mpa_layer, &mpa_br);    if(len < 0) {      stream_skip(demuxer->stream,-3);      continue;    }    if (s->eof)    {    	break;    	    }    stream_skip(demuxer->stream,len-4);        if(stream_tell(s) >= s->end_pos-128-len)    	break;    count++;  }	s->eof = 0;    return count;}static int demux_audio_open(demuxer_t* demuxer) {  stream_t *s;  sh_audio_t* sh_audio;  uint8_t hdr[HDR_SIZE];  int frmt = 0, n = 0, step;  off_t st_pos = 0, next_frame_pos = 0;  // mp3_hdrs list is sorted first by next_frame_pos and then by frame_pos  mp3_hdr_t *mp3_hdrs = NULL, *mp3_found = NULL;  da_priv_t* priv;    s = demuxer->stream;  stream_read(s, hdr, HDR_SIZE);  while(n < 30000 && !s->eof) {    int mp3_freq, mp3_chans, mp3_flen, mpa_layer, mpa_spf, mpa_br;    st_pos = stream_tell(s) - HDR_SIZE;    step = 1;    if( hdr[0] == 'R' && hdr[1] == 'I' && hdr[2] == 'F' && hdr[3] == 'F' ) {      stream_skip(s,4);      if(s->eof)	break;      stream_read(s,hdr,4);      if(s->eof)	break;      if(hdr[0] != 'W' || hdr[1] != 'A' || hdr[2] != 'V'  || hdr[3] != 'E' )	stream_skip(s,-8);      else      // We found wav header. Now we can have 'fmt ' or a mp3 header      // empty the buffer	step = 4;    } else if( hdr[0] == 'I' && hdr[1] == 'D' && hdr[2] == '3' && (hdr[3] >= 2)) {      int len;      stream_skip(s,2);      stream_read(s,hdr,4);      len = (hdr[0]<<21) | (hdr[1]<<14) | (hdr[2]<<7) | hdr[3];      stream_skip(s,len);      step = 4;    } else if( hdr[0] == 'f' && hdr[1] == 'm' && hdr[2] == 't' && hdr[3] == ' ' ) {      frmt = WAV;      break;          } else if((mp3_flen = mp_get_mp3_header(hdr, &mp3_chans, &mp3_freq,                                &mpa_spf, &mpa_layer, &mpa_br)) > 0) {      mp3_found = add_mp3_hdr(&mp3_hdrs, st_pos, mp3_chans, mp3_freq,                              mpa_spf, mpa_layer, mpa_br, mp3_flen);      if (mp3_found) {        frmt = MP3;        break;      }    } else if( hdr[0] == 'f' && hdr[1] == 'L' && hdr[2] == 'a' && hdr[3] == 'C' ) {      frmt = fLaC;      break;    }    // Add here some other audio format detection    if(step < HDR_SIZE)      memmove(hdr,&hdr[step],HDR_SIZE-step);    stream_read(s, &hdr[HDR_SIZE - step], step);    n++;  }  free_mp3_hdrs(&mp3_hdrs);  if(!frmt)    return 0;  sh_audio = new_sh_audio(demuxer,0);  switch(frmt) {  case MP3:    sh_audio->format = (mp3_found->mpa_layer < 3 ? 0x50 : 0x55);    demuxer->movi_start = mp3_found->frame_pos;    next_frame_pos = mp3_found->next_frame_pos;    sh_audio->audio.dwSampleSize= 0;    sh_audio->audio.dwScale = mp3_found->mpa_spf;    sh_audio->audio.dwRate = mp3_found->mp3_freq;    sh_audio->wf = malloc(sizeof(WAVEFORMATEX));    sh_audio->wf->wFormatTag = sh_audio->format;    sh_audio->wf->nChannels = mp3_found->mp3_chans;    sh_audio->wf->nSamplesPerSec = mp3_found->mp3_freq;    sh_audio->wf->nAvgBytesPerSec = mp3_found->mpa_br * (1000 / 8);    sh_audio->wf->nBlockAlign = mp3_found->mpa_spf;    sh_audio->wf->wBitsPerSample = 16;    sh_audio->wf->cbSize = 0;        sh_audio->i_bps = sh_audio->wf->nAvgBytesPerSec;          //F("get totla time %d %d\n",sh_audio->audio.dwRate,sh_audio->wf->nBlockAlign);      int dcount = mp3_total_framecount(demuxer);           mp3_totaltime = (float)(dcount * sh_audio->wf->nBlockAlign / sh_audio->audio.dwRate);

⌨️ 快捷键说明

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