读包操作分析
-
//链表元素结构体
-
typedef struct MyAVPacketList {
-
AVPacket pkt;
-
struct MyAVPacketList *next;//指向下一个元素
-
int serial;
-
} MyAVPacketList;
-
//包队列,先进FIFO队列
-
typedef struct PacketQueue {
-
MyAVPacketList *first_pkt, *last_pkt;//队首,队尾指针
扫描二维码关注公众号,回复: 3123117 查看本文章 -
int nb_packets;//包数量,也就是队列元素数量
-
int size;//占用内存大小
-
int abort_request;//用户退出请求标志
-
int serial;//序列,作拖动时用,作为区分前后帧序列
-
SDL_mutex *mutex;//互斥锁
-
SDL_cond *cond;//条件锁
-
} PacketQueue;
入队操作:
-
static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
-
{
-
MyAVPacketList *pkt1;
-
//用户放弃,返回
-
if (q->abort_request)
-
return -1;
-
pkt1 = (MyAVPacketList*)av_malloc(sizeof(MyAVPacketList));
-
if (!pkt1)
-
return -1;
-
pkt1->pkt = *pkt;
-
pkt1->next = NULL;
-
if (pkt == &flush_pkt)//入队的包为flush标签包,serial自加,表示另外一个系列
-
q->serial++;
-
pkt1->serial = q->serial;
-
if (!q->last_pkt)//队列为空
-
q->first_pkt = pkt1;
-
else
-
q->last_pkt->next = pkt1;//不为空,加到队尾
-
q->last_pkt = pkt1;//将队尾设为当前入队包
-
q->nb_packets++;//数量增加
-
q->size += pkt1->pkt.size + sizeof(*pkt1);//更新内存使用量
-
/* XXX: should duplicate packet data in DV case */
-
SDL_CondSignal(q->cond);//条件变量解锁
-
return 0;
-
}
-
//入队API,调用此函数是线程安全的
-
static int packet_queue_put(PacketQueue *q, AVPacket *pkt)
-
{
-
int ret;
-
/* duplicate the packet */
-
if (pkt != &flush_pkt && av_dup_packet(pkt) < 0)
-
return -1;
-
SDL_LockMutex(q->mutex);
-
ret = packet_queue_put_private(q, pkt);
-
SDL_UnlockMutex(q->mutex);
-
if (pkt != &flush_pkt && ret < 0)
-
av_free_packet(pkt);
-
return ret;
-
}
由于视频解码线程,音频播放(主线程)同时访问包队列,所以需要加互斥锁。
-
//将一个空包入队
-
static int packet_queue_put_nullpacket(PacketQueue *q, int stream_index)
-
{
-
AVPacket pkt1, *pkt = &pkt1;
-
av_init_packet(pkt);
-
pkt->data = NULL;
-
pkt->size = 0;
-
pkt->stream_index = stream_index;
-
return packet_queue_put(q, pkt);
-
}
-
//队列初始化
-
static void packet_queue_init(PacketQueue *q)
-
{
-
memset(q, 0, sizeof(PacketQueue));
-
q->mutex = SDL_CreateMutex();
-
q->cond = SDL_CreateCond();
-
q->abort_request = 1;
-
}
-
//释放队列空间
-
static void packet_queue_destroy(PacketQueue *q)
-
{
-
packet_queue_flush(q);
-
SDL_DestroyMutex(q->mutex);
-
SDL_DestroyCond(q->cond);
-
}
-
//用户取消
-
static void packet_queue_abort(PacketQueue *q)
-
{
-
SDL_LockMutex(q->mutex);
-
q->abort_request = 1;
-
SDL_CondSignal(q->cond);
-
SDL_UnlockMutex(q->mutex);
-
}
-
//队列开启
-
static void packet_queue_start(PacketQueue *q)
-
{
-
SDL_LockMutex(q->mutex);
-
q->abort_request = 0;
-
packet_queue_put_private(q, &flush_pkt);
-
SDL_UnlockMutex(q->mutex);
-
}
-
/* return < 0 if aborted, 0 if no packet and > 0 if packet. */
-
//出队操作
-
static int packet_queue_get(PacketQueue *q, AVPacket *pkt, int block, int *serial)
-
{
-
MyAVPacketList *pkt1;
-
int ret;
-
SDL_LockMutex(q->mutex);
-
for (;;) {
-
if (q->abort_request) {
-
ret = -1;
-
break;
-
}
-
//取队头元素
-
pkt1 = q->first_pkt;
-
if (pkt1) {
-
q->first_pkt = pkt1->next;
-
if (!q->first_pkt)
-
q->last_pkt = NULL;
-
q->nb_packets--;
-
q->size -= pkt1->pkt.size + sizeof(*pkt1);
-
*pkt = pkt1->pkt;
-
if (serial)
-
*serial = pkt1->serial;
-
av_free(pkt1);
-
ret = 1;
-
break;
-
} else if (!block) {
-
ret = 0;
-
break;
-
} else {//队列为空,阻塞在队列条件变量上
-
SDL_CondWait(q->cond, q->mutex);
-
}
-
}
-
SDL_UnlockMutex(q->mutex);
-
return ret;
-
}
-
//读取一帧
-
int av_read_frame(AVFormatContext *s, AVPacket *pkt)
-
{
-
const int genpts = s->flags & AVFMT_FLAG_GENPTS;
-
int eof = 0;
-
int ret;
-
AVStream *st;
-
//如果没有设置生成时间戳标志
-
if (!genpts) {
-
//包FIFO队列不为空,从队列中出队,否则从文件中读取
-
ret = s->packet_buffer ?
-
read_from_packet_buffer(&s->packet_buffer, &s->packet_buffer_end, pkt) :
-
read_frame_internal(s, pkt);
-
if (ret < 0)
-
return ret;
-
goto return_packet;
-
}
-
//设置了生成时间戳
-
for (;;) {
-
//队列头
-
AVPacketList *pktl = s->packet_buffer;
-
if (pktl) {
-
AVPacket *next_pkt = &pktl->pkt;
-
//如果解码时间戳有效
-
if (next_pkt->dts != AV_NOPTS_VALUE) {
-
int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;//获取时间戳压缩位数
-
// last dts seen for this stream. if any of packets following
-
// current one had no dts, we will set this to AV_NOPTS_VALUE.
-
int64_t last_dts = next_pkt->dts;
-
while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {
-
//时间戳无效
-
if (pktl->pkt.stream_index == next_pkt->stream_index &&
-
(av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0)) {
-
if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { //not b frame
-
next_pkt->pts = pktl->pkt.dts;
-
}
-
if (last_dts != AV_NOPTS_VALUE) {
-
// Once last dts was set to AV_NOPTS_VALUE, we don't change it.
-
last_dts = pktl->pkt.dts;
-
}
-
}
-
pktl = pktl->next;
-
}
-
if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) {
-
// Fixing the last reference frame had none pts issue (For MXF etc).
-
// We only do this when
-
// 1. eof.
-
// 2. we are not able to resolve a pts value for current packet.
-
// 3. the packets for this stream at the end of the files had valid dts.
-
next_pkt->pts = last_dts + next_pkt->duration;
-
}
-
pktl = s->packet_buffer;
-
}
-
/* read packet from packet buffer, if there is data */
-
if (!(next_pkt->pts == AV_NOPTS_VALUE &&
-
next_pkt->dts != AV_NOPTS_VALUE && !eof)) {
-
ret = read_from_packet_buffer(&s->packet_buffer,
-
&s->packet_buffer_end, pkt);
-
goto return_packet;
-
}
-
}
-
ret = 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);
-
}
-
return_packet:
-
st = s->streams[pkt->stream_index];
-
if (st->skip_samples) {
-
uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
-
if (p) {
-
AV_WL32(p, st->skip_samples);
-
av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d\n", st->skip_samples);
-
}
-
st->skip_samples = 0;
-
}
-
if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) {
-
ff_reduce_index(s, st->index);
-
av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME);
-
}
-
if (is_relative(pkt->dts))
-
pkt->dts -= RELATIVE_TS_BASE;
-
if (is_relative(pkt->pts))
-
pkt->pts -= RELATIVE_TS_BASE;
-
return ret;
-
}
-
//flush 队列
-
static void packet_queue_flush(PacketQueue *q)
-
{
-
MyAVPacketList *pkt, *pkt1;
-
SDL_LockMutex(q->mutex);
-
for (pkt = q->first_pkt; pkt != NULL; pkt = pkt1) {
-
pkt1 = pkt->next;
-
av_free_packet(&pkt->pkt);
-
av_freep(&pkt);
-
}
-
q->last_pkt = NULL;
-
q->first_pkt = NULL;
-
q->nb_packets = 0;
-
q->size = 0;
-
SDL_UnlockMutex(q->mutex);
-
}
ffmpeg纯属个人喜好而了解,定有许多疏漏之处,欢迎指正!