ffmpeg框架阅读笔记一:读取数据帧函数 int av_read_frame(AVFormatContext *s, AVPacket *pkt)

来源:互联网 发布:刺客信条系列优化 编辑:程序博客网 时间:2024/05/21 14:04

做音频播放,数据源从完整音频文件变成了网络拉取音频流到缓冲区,实现片段流的播放。分析av_read_frame过程,自定义获取数据源的功能。重点查找如何读入数据源。

首先分析函数av_read_frame。

[cpp] view plain copy
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
{
//包含AVPacket结构体的链表结点
AVPacketList *pktl;
int eof=0;
const int genpts= s->flags & AVFMT_FLAG_GENPTS;

for(;;){      pktl = s->packet_buffer;      if (pktl) {          AVPacket *next_pkt= &pktl->pkt;          if(genpts && next_pkt->dts != AV_NOPTS_VALUE){              int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;              while(pktl && next_pkt->pts == AV_NOPTS_VALUE){                  if(   pktl->pkt.stream_index == next_pkt->stream_index                     && (0 > av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)))                     && av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { //not b frame                      next_pkt->pts= pktl->pkt.dts;                  }                  pktl= pktl->next;              }              pktl = s->packet_buffer;          }          if(   next_pkt->pts != AV_NOPTS_VALUE             || next_pkt->dts == AV_NOPTS_VALUE             || !genpts || eof){              /* read packet from packet buffer, if there is data */              *pkt = *next_pkt;              s->packet_buffer = pktl->next;              av_free(pktl);              return 0;          }      }      if(genpts){          //这里读取数据           int ret= av_read_frame_internal(s, pkt);          if(ret<0){              if(pktl && ret != AVERROR(EAGAIN)){                  eof=1;                  continue;              }else                  return ret;          }          if(av_dup_packet(add_to_pktbuf(&s->packet_buffer, pkt,                                         &s->packet_buffer_end)) < 0)              return AVERROR(ENOMEM);      }else{          assert(!s->packet_buffer);          return av_read_frame_internal(s, pkt);      }  }  

}
上面代码找到av_read_frame_internal函数。其他代码不加分析。看的也不是很懂。接下来是av_read_frame_internal。

[cpp] view plain copy
static int av_read_frame_internal(AVFormatContext *s, AVPacket *pkt)
{
AVStream *st;
int len, ret, i;
//初始化pkt的各个成员
av_init_packet(pkt);

for(;;) {      /* select current input stream component */      //获得当前输入流      st = s->cur_st;      if (st) {          if (!st->need_parsing || !st->parser) {              /* no parsing needed: we just output the packet as is */              /* raw data support */              *pkt = st->cur_pkt;              st->cur_pkt.data= NULL;              st->cur_pkt.side_data_elems = 0;              st->cur_pkt.side_data = NULL;              compute_pkt_fields(s, st, NULL, pkt);              s->cur_st = NULL;              if ((s->iformat->flags & AVFMT_GENERIC_INDEX) &&                  (pkt->flags & AV_PKT_FLAG_KEY) && pkt->dts != AV_NOPTS_VALUE) {                  ff_reduce_index(s, st->index);                  av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME);              }              break;          } else if (st->cur_len > 0 && st->discard < AVDISCARD_ALL) {              len = av_parser_parse2(st->parser, st->codec, &pkt->data, &pkt->size,                                     st->cur_ptr, st->cur_len,                                     st->cur_pkt.pts, st->cur_pkt.dts,                                     st->cur_pkt.pos);              st->cur_pkt.pts = AV_NOPTS_VALUE;              st->cur_pkt.dts = AV_NOPTS_VALUE;              /* increment read pointer */              st->cur_ptr += len;              st->cur_len -= len;              /* return packet if any */              if (pkt->size) {              got_packet:                  pkt->duration = 0;                  pkt->stream_index = st->index;                  pkt->pts = st->parser->pts;                  pkt->dts = st->parser->dts;                  pkt->pos = st->parser->pos;                  if(pkt->data == st->cur_pkt.data && pkt->size == st->cur_pkt.size){                      s->cur_st = NULL;                      pkt->destruct= st->cur_pkt.destruct;                      st->cur_pkt.destruct= NULL;                      st->cur_pkt.data    = NULL;                      assert(st->cur_len == 0);                  }else{                  pkt->destruct = NULL;                  }                  compute_pkt_fields(s, st, st->parser, pkt);                  if((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY){                      int64_t pos= (st->parser->flags & PARSER_FLAG_COMPLETE_FRAMES) ? pkt->pos : st->parser->frame_offset;                      ff_reduce_index(s, st->index);                      av_add_index_entry(st, pos, pkt->dts,                                         0, 0, AVINDEX_KEYFRAME);                  }                  break;              }          } else {              /* free packet */              av_free_packet(&st->cur_pkt);              s->cur_st = NULL;          }      } else { //当前输入流内容不存在 去数据源读取          AVPacket cur_pkt;          /* read next packet */          //读下一个数据包          ret = av_read_packet(s, &cur_pkt);          if (ret < 0) {              if (ret == AVERROR(EAGAIN))                  return ret;              /* return the last frames, if any */              for(i = 0; i < s->nb_streams; i++) {                  st = s->streams[i];                  if (st->parser && st->need_parsing) {                      av_parser_parse2(st->parser, st->codec,                                      &pkt->data, &pkt->size,                                      NULL, 0,                                      AV_NOPTS_VALUE, AV_NOPTS_VALUE,                                      AV_NOPTS_VALUE);                      if (pkt->size)                          goto got_packet;                  }              }              /* no more packets: really terminate parsing */              return ret;          }          st = s->streams[cur_pkt.stream_index];          st->cur_pkt= cur_pkt;          if(st->cur_pkt.pts != AV_NOPTS_VALUE &&             st->cur_pkt.dts != AV_NOPTS_VALUE &&             st->cur_pkt.pts < st->cur_pkt.dts){              av_log(s, AV_LOG_WARNING, "Invalid timestamps stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d\n",                  st->cur_pkt.stream_index,                  st->cur_pkt.pts,                  st->cur_pkt.dts,                  st->cur_pkt.size);  

// av_free_packet(&st->cur_pkt);
// return -1;
}

        if(s->debug & FF_FDEBUG_TS)              av_log(s, AV_LOG_DEBUG, "av_read_packet stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d, duration=%d, flags=%d\n",                  st->cur_pkt.stream_index,                  st->cur_pkt.pts,                  st->cur_pkt.dts,                  st->cur_pkt.size,                  st->cur_pkt.duration,                  st->cur_pkt.flags);          s->cur_st = st;          st->cur_ptr = st->cur_pkt.data;          st->cur_len = st->cur_pkt.size;          if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) {              st->parser = av_parser_init(st->codec->codec_id);              if (!st->parser) {                  /* no parser available: just output the raw packets */                  st->need_parsing = AVSTREAM_PARSE_NONE;              }else if(st->need_parsing == AVSTREAM_PARSE_HEADERS){                  st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES;              }else if(st->need_parsing == AVSTREAM_PARSE_FULL_ONCE){                  st->parser->flags |= PARSER_FLAG_ONCE;              }          }      }  }  if(s->debug & FF_FDEBUG_TS)      av_log(s, AV_LOG_DEBUG, "av_read_frame_internal stream=%d, pts=%"PRId64", dts=%"PRId64", size=%d, duration=%d, flags=%d\n",          pkt->stream_index,          pkt->pts,          pkt->dts,          pkt->size,          pkt->duration,          pkt->flags);  return 0;  

}

找到函数int av_read_packet(AVFormatContext *s, AVPacket *pkt)
[cpp] view plain copy
int av_read_packet(AVFormatContext *s, AVPacket *pkt)
{
int ret, i;
AVStream *st;

for(;;){      AVPacketList *pktl = s->raw_packet_buffer;     //格式上下文存在原生的包数据      if (pktl) {          *pkt = pktl->pkt;          if(s->streams[pkt->stream_index]->request_probe <= 0){              s->raw_packet_buffer = pktl->next;              s->raw_packet_buffer_remaining_size += pkt->size;              av_free(pktl);              return 0;          }      }      av_init_packet(pkt);      //原生包数据不存在 通过AVInputFormat的read_packet函数指针成员来调用函数获取数据源      //AVInputFormat是不同格式数据的操作函数集合。在注册函数中初始化所有格式的该结构体变量。      ret= s->iformat->read_packet(s, pkt);      if (ret < 0) {          if (!pktl || ret == AVERROR(EAGAIN))              return ret;          for (i = 0; i < s->nb_streams; i++)              if(s->streams[i]->request_probe > 0)                  s->streams[i]->request_probe = -1;          continue;      }      if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA))          av_packet_merge_side_data(pkt);      st= s->streams[pkt->stream_index];      switch(st->codec->codec_type){      case AVMEDIA_TYPE_VIDEO:          if(s->video_codec_id)   st->codec->codec_id= s->video_codec_id;          break;      case AVMEDIA_TYPE_AUDIO:          if(s->audio_codec_id)   st->codec->codec_id= s->audio_codec_id;          break;      case AVMEDIA_TYPE_SUBTITLE:          if(s->subtitle_codec_id)st->codec->codec_id= s->subtitle_codec_id;          break;      }      if(!pktl && st->request_probe <= 0)          return ret;      add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end);      s->raw_packet_buffer_remaining_size -= pkt->size;      if(st->request_probe>0){          AVProbeData *pd = &st->probe_data;          int end;          av_log(s, AV_LOG_DEBUG, "probing stream %d pp:%d\n", st->index, st->probe_packets);          --st->probe_packets;          pd->buf = av_realloc(pd->buf, pd->buf_size+pkt->size+AVPROBE_PADDING_SIZE);          memcpy(pd->buf+pd->buf_size, pkt->data, pkt->size);          pd->buf_size += pkt->size;          memset(pd->buf+pd->buf_size, 0, AVPROBE_PADDING_SIZE);          end=    s->raw_packet_buffer_remaining_size <= 0               || st->probe_packets<=0;          if(end || av_log2(pd->buf_size) != av_log2(pd->buf_size - pkt->size)){              int score= set_codec_from_probe_data(s, st, pd);              if(    (st->codec->codec_id != CODEC_ID_NONE && score > AVPROBE_SCORE_MAX/4)                  || end){                  pd->buf_size=0;                  av_freep(&pd->buf);                  st->request_probe= -1;                  if(st->codec->codec_id != CODEC_ID_NONE){                  av_log(s, AV_LOG_DEBUG, "probed stream %d\n", st->index);                  }else                      av_log(s, AV_LOG_WARNING, "probed stream %d failed\n", st->index);              }          }      }  }  

}

分析AVInpuFormat结构体初始化过程
[cpp] view plain copy
AVInputFormat ff_flv_demuxer = {
“flv”,
NULL_IF_CONFIG_SMALL(“FLV format”),
sizeof(FLVContext),
flv_probe,
flv_read_header,
//读数据包的函数指针
flv_read_packet,
.read_seek = flv_read_seek,

if 0

.read_seek2 = flv_read_seek2,  

endif

.extensions = "flv",  .value = CODEC_ID_FLV1,  

};

分析flv_read_packet
[cpp] view plain copy
static int flv_read_packet(AVFormatContext *s, AVPacket *pkt)
{
FLVContext *flv = s->priv_data;
int ret, i, type, size, flags, is_audio;
int64_t next, pos;
int64_t dts, pts = AV_NOPTS_VALUE;
AVStream *st = NULL;

for(;;avio_skip(s->pb, 4)){ /* pkt size is repeated at end. skip it */
pos = avio_tell(s->pb);
type = avio_r8(s->pb);
size = avio_rb24(s->pb);
dts = avio_rb24(s->pb);
dts |= avio_r8(s->pb) << 24;
av_dlog(s, “type:%d, size:%d, dts:%”PRId64”\n”, type, size, dts);
if (url_feof(s->pb))
return AVERROR_EOF;
avio_skip(s->pb, 3); /* stream id, always 0 */
flags = 0;

if(size == 0)      continue;  next= size + avio_tell(s->pb);  if (type == FLV_TAG_TYPE_AUDIO) {      is_audio=1;      flags = avio_r8(s->pb);      size--;  } else if (type == FLV_TAG_TYPE_VIDEO) {      is_audio=0;      flags = avio_r8(s->pb);      size--;      if ((flags & 0xf0) == 0x50) /* video info / command frame */          goto skip;  } else {      if (type == FLV_TAG_TYPE_META && size > 13+1+4)          flv_read_metabody(s, next);      else /* skip packet */          av_log(s, AV_LOG_DEBUG, "skipping flv packet: type %d, size %d, flags %d\n", type, size, flags);  skip:      avio_seek(s->pb, next, SEEK_SET);      continue;  }  /* skip empty data packets */  if (!size)      continue;  /* now find stream */  for(i=0;i<s->nb_streams;i++) {      st = s->streams[i];      if (st->id == is_audio)          break;  }  if(i == s->nb_streams){      av_log(s, AV_LOG_ERROR, "invalid stream\n");      st= create_stream(s, is_audio);      s->ctx_flags &= ~AVFMTCTX_NOHEADER;  }  av_dlog(s, "%d %X %d \n", is_audio, flags, st->discard);  if(  (st->discard >= AVDISCARD_NONKEY && !((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY ||         is_audio))     ||(st->discard >= AVDISCARD_BIDIR  &&  ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_DISP_INTER && !is_audio))     || st->discard >= AVDISCARD_ALL     ){      avio_seek(s->pb, next, SEEK_SET);      continue;  }  if ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY)      av_add_index_entry(st, pos, dts, size, 0, AVINDEX_KEYFRAME);  break;  

}

// if not streamed and no duration from metadata then seek to end to find the duration from the timestamps  if(s->pb->seekable && (!s->duration || s->duration==AV_NOPTS_VALUE)){      int size;      const int64_t pos= avio_tell(s->pb);      const int64_t fsize= avio_size(s->pb);      avio_seek(s->pb, fsize-4, SEEK_SET);      size= avio_rb32(s->pb);      avio_seek(s->pb, fsize-3-size, SEEK_SET);      if(size == avio_rb24(s->pb) + 11){          uint32_t ts = avio_rb24(s->pb);          ts |= avio_r8(s->pb) << 24;          s->duration = ts * (int64_t)AV_TIME_BASE / 1000;      }      avio_seek(s->pb, pos, SEEK_SET);  }  if(is_audio){      if(!st->codec->channels || !st->codec->sample_rate || !st->codec->bits_per_coded_sample) {          st->codec->channels = (flags & FLV_AUDIO_CHANNEL_MASK) == FLV_STEREO ? 2 : 1;          st->codec->sample_rate = (44100 << ((flags & FLV_AUDIO_SAMPLERATE_MASK) >> FLV_AUDIO_SAMPLERATE_OFFSET) >> 3);          st->codec->bits_per_coded_sample = (flags & FLV_AUDIO_SAMPLESIZE_MASK) ? 16 : 8;      }      if(!st->codec->codec_id){          flv_set_audio_codec(s, st, flags & FLV_AUDIO_CODECID_MASK);      }  }else{      size -= flv_set_video_codec(s, st, flags & FLV_VIDEO_CODECID_MASK);  }  if (st->codec->codec_id == CODEC_ID_AAC ||      st->codec->codec_id == CODEC_ID_H264) {      int type = avio_r8(s->pb);      size--;      if (st->codec->codec_id == CODEC_ID_H264) {          int32_t cts = (avio_rb24(s->pb)+0xff800000)^0xff800000; // sign extension          pts = dts + cts;          if (cts < 0) { // dts are wrong              flv->wrong_dts = 1;              av_log(s, AV_LOG_WARNING, "negative cts, previous timestamps might be wrong\n");          }          if (flv->wrong_dts)              dts = AV_NOPTS_VALUE;      }      if (type == 0) {          if ((ret = flv_get_extradata(s, st, size)) < 0)              return ret;          if (st->codec->codec_id == CODEC_ID_AAC) {              MPEG4AudioConfig cfg;              ff_mpeg4audio_get_config(&cfg, st->codec->extradata,                                       st->codec->extradata_size);              st->codec->channels = cfg.channels;              if (cfg.ext_sample_rate)                  st->codec->sample_rate = cfg.ext_sample_rate;              else                  st->codec->sample_rate = cfg.sample_rate;              av_dlog(s, "mp4a config channels %d sample rate %d\n",                      st->codec->channels, st->codec->sample_rate);          }          ret = AVERROR(EAGAIN);          goto leave;      }  }  /* skip empty data packets */  if (!size) {      ret = AVERROR(EAGAIN);      goto leave;  }  

//从AVIOContext读取数据
ret= av_get_packet(s->pb, pkt, size);
if (ret < 0) {
return AVERROR(EIO);
}
/* note: we need to modify the packet size here to handle the last
packet */
pkt->size = ret;
pkt->dts = dts;
pkt->pts = pts == AV_NOPTS_VALUE ? dts : pts;
pkt->stream_index = st->index;

if (is_audio || ((flags & FLV_VIDEO_FRAMETYPE_MASK) == FLV_FRAME_KEY))      pkt->flags |= AV_PKT_FLAG_KEY;  

leave:
avio_skip(s->pb, 4);
return ret;
}

分析av_get_packet()
[cpp] view plain copy
int av_get_packet(AVIOContext *s, AVPacket *pkt, int size)
{
//pkt分配空间并初始化
int ret= av_new_packet(pkt, size);

if(ret<0)      return ret;  pkt->pos= avio_tell(s);  //从io上下文读取数据  ret= avio_read(s, pkt->data, size);  if(ret<=0)      av_free_packet(pkt);  else      av_shrink_packet(pkt, ret);  return ret;  

}

分析avio_read
[cpp] view plain copy
int avio_read(AVIOContext *s, unsigned char *buf, int size)
{
int len, size1;

size1 = size;  while (size > 0) {      len = s->buf_end - s->buf_ptr;      if (len > size)          len = size;      if (len == 0) {          if(size > s->buffer_size && !s->update_checksum){              if(s->read_packet)                  //调用AVIOContext的成员  read_packet函数指针                  len = s->read_packet(s->opaque, buf, size);              if (len <= 0) {                  /* do not modify buffer if EOF reached so that a seek back can                 be done without rereading data */                  s->eof_reached = 1;                  if(len<0)                      s->error= len;                  break;              } else {                  s->pos += len;                  size -= len;                  buf += len;                  s->buf_ptr = s->buffer;                  s->buf_end = s->buffer/* + len*/;              }          }else{              fill_buffer(s);              len = s->buf_end - s->buf_ptr;              if (len == 0)                  break;          }      } else {          memcpy(buf, s->buf_ptr, len);          buf += len;          s->buf_ptr += len;          size -= len;      }  }  if (size1 == size) {      if (s->error)      return s->error;      if (url_feof(s))   return AVERROR_EOF;  }  return size1 - size;  

}

AVIOContext结构体需要由avformat_open_input来进行初始化。对于该函数打开媒体文件的分析,见收藏的一篇文章。目前根据需要要进行自定义的AVIOContext结构体变量的初始化。贴出ffmpeg初始化其的代码,参考进行自定义初始化。
[cpp] view plain copy
int ffio_fdopen(AVIOContext **s, URLContext *h)
{
uint8_t *buffer;
int buffer_size, max_packet_size;

max_packet_size = h->max_packet_size;  if (max_packet_size) {      buffer_size = max_packet_size; /* no need to bufferize more than one packet */  } else {      buffer_size = IO_BUFFER_SIZE;  }  buffer = av_malloc(buffer_size);  if (!buffer)      return AVERROR(ENOMEM);  *s = av_mallocz(sizeof(AVIOContext));  if(!*s) {      av_free(buffer);      return AVERROR(ENOMEM);  }  //初始化AVIOContext  if (ffio_init_context(*s, buffer, buffer_size,                    h->flags & AVIO_FLAG_WRITE, h,                    (void*)ffurl_read, (void*)ffurl_write, (void*)ffurl_seek) < 0) {      av_free(buffer);      av_freep(s);      return AVERROR(EIO);  }  

if FF_API_OLD_AVIO

(*s)->is_streamed = h->is_streamed;  

endif

(*s)->seekable = h->is_streamed ? 0 : AVIO_SEEKABLE_NORMAL;  (*s)->max_packet_size = max_packet_size;  if(h->prot) {      (*s)->read_pause = (int (*)(void *, int))h->prot->url_read_pause;      (*s)->read_seek  = (int64_t (*)(void *, int, int64_t, int))h->prot->url_read_seek;  }  return 0;  

}

int ffio_init_context(AVIOContext *s,
unsigned char *buffer,
int buffer_size,
int write_flag,
void *opaque,
int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),
int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),
int64_t (*seek)(void *opaque, int64_t offset, int whence))
{
s->buffer = buffer;
s->buffer_size = buffer_size;
s->buf_ptr = buffer;
s->opaque = opaque;
url_resetbuf(s, write_flag ? AVIO_FLAG_WRITE : AVIO_FLAG_READ);
s->write_packet = write_packet;
s->read_packet = read_packet;
s->seek = seek;
s->pos = 0;
s->must_flush = 0;
s->eof_reached = 0;
s->error = 0;

if FF_API_OLD_AVIO

s->is_streamed = 0;  

endif

s->seekable = AVIO_SEEKABLE_NORMAL;  s->max_packet_size = 0;  s->update_checksum= NULL;  if(!read_packet && !write_flag){      s->pos = buffer_size;      s->buf_end = s->buffer + buffer_size;  }  s->read_pause = NULL;  s->read_seek  = NULL;  return 0;  

}
经过上述分析,需要根据项目需要自定义AVIOContext,设置数据源,设置各类回调函数。
网上找到一段探测网络流格式的方法,实现相似的功能。没有经过测试,先贴出来,后面进行测试。

[cpp] view plain copy

include “utils.h”

include

include

include

define BUF_SIZE 4096*500

int main(int argc, char** argv) {

init_queue(&recvqueue, 1024*500);

udpParam.argv = argv;
udpParam.queue = &recvqueue;
uint8_t *buf = av_mallocz(sizeof(uint8_t)*BUF_SIZE);

//UDP接收线程
pthread_t udp_recv_thread;
pthread_create(&udp_recv_thread, NULL, udp_ts_recv, &udpParam);
pthread_detach(udp_recv_thread);

av_register_all();

AVCodec *pVideoCodec, *pAudioCodec;
AVCodecContext *pVideoCodecCtx = NULL;
AVCodecContext *pAudioCodecCtx = NULL;
AVIOContext * pb = NULL;
AVInputFormat *piFmt = NULL;
AVFormatContext *pFmt = NULL;

//step1:申请一个AVIOContext
pb = avio_alloc_context(buf, BUF_SIZE, 0, NULL, read_data, NULL, NULL);
if (!pb) {
fprintf(stderr, “avio alloc failed!\n”);
return -1;
}
//step2:探测流格式
if (av_probe_input_buffer(pb, &piFmt, “”, NULL, 0, 0) < 0) {
fprintf(stderr, “probe failed!\n”);
return -1;
} else {
fprintf(stdout, “probe success!\n”);
fprintf(stdout, “format: %s[%s]\n”, piFmt->name, piFmt->long_name);
}

pFmt = avformat_alloc_context();
pFmt->pb = pb; //step3:这一步很关键
//step4:打开流
if (avformat_open_input(&pFmt, “”, piFmt, NULL) < 0) {
fprintf(stderr, “avformat open failed.\n”);
return -1;
} else {
fprintf(stdout, “open stream success!\n”);
}
//以下就和文件处理一致了
if (av_find_stream_info(pFmt) < 0) {
fprintf(stderr, “could not fine stream.\n”);
return -1;
}

av_dump_format(pFmt, 0, “”, 0);

int videoindex = -1;
int audioindex = -1;
for (int i = 0; i < pFmt->nb_streams; i++) {
if ( (pFmt->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) &&
(videoindex < 0) ) {
videoindex = i;
}
if ( (pFmt->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) &&
(audioindex < 0) ) {
audioindex = i;
}
}

if (videoindex < 0 || audioindex < 0) {
fprintf(stderr, “videoindex=%d, audioindex=%d\n”, videoindex, audioindex);
return -1;
}

AVStream *pVst,*pAst;
pVst = pFmt->streams[videoindex];
pAst = pFmt->streams[audioindex];

pVideoCodecCtx = pVst->codec;
pAudioCodecCtx = pAst->codec;

pVideoCodec = avcodec_find_decoder(pVideoCodecCtx->codec_id);
if (!pVideoCodec) {
fprintf(stderr, “could not find video decoder!\n”);
return -1;
}
if (avcodec_open(pVideoCodecCtx, pVideoCodec) < 0) {
fprintf(stderr, “could not open video codec!\n”);
return -1;
}

pAudioCodec = avcodec_find_decoder(pAudioCodecCtx->codec_id);
if (!pAudioCodec) {
fprintf(stderr, “could not find audio decoder!\n”);
return -1;
}
if (avcodec_open(pAudioCodecCtx, pAudioCodec) < 0) {
fprintf(stderr, “could not open audio codec!\n”);
return -1;
}

int got_picture;
uint8_t samples[AVCODEC_MAX_AUDIO_FRAME_SIZE*3/2];
AVFrame *pframe = avcodec_alloc_frame();
AVPacket pkt;
av_init_packet(&pkt);

while(1) {
if (av_read_frame(pFmt, &pkt) >= 0) {

if (pkt.stream_index == videoindex) {
fprintf(stdout, “pkt.size=%d,pkt.pts=%lld, pkt.data=0x%x.”, pkt.size, pkt.pts,(unsigned int)pkt.data);
avcodec_decode_video2(pVideoCodecCtx, pframe, &got_picture, &pkt);
if (got_picture) {
fprintf(stdout, “decode one video frame!\n”);
}
}else if (pkt.stream_index == audioindex) {
int frame_size = AVCODEC_MAX_AUDIO_FRAME_SIZE*3/2;
if (avcodec_decode_audio3(pAudioCodecCtx, (int16_t *)samples, &frame_size, &pkt) >= 0) {
fprintf(stdout, “decode one audio frame!\n”);
}
}
av_free_packet(&pkt);
}
}

av_free(buf);
av_free(pframe);
free_queue(&recvqueue);
return 0;
}
这段代码作者为windragon0419,在此表示感谢。
后面经过测试以后,记录下解决过程。

原创粉丝点击