当前位置:网站首页>Ijkplayer source code ---packetqueue

Ijkplayer source code ---packetqueue

2022-06-13 02:43:00 Original general breaking

We will not discuss in this article PacketQueue stay ijk Where to use , Only from PacketQueue Start with the code

Let's start with two structures

typedef struct MyAVPacketList {
    AVPacket pkt;
    struct MyAVPacketList *next;
    int serial;
} MyAVPacketList;
 You can see through the structure MyAVPacketList Is a node of a linked list , Each node contains unpacked AVPacket


typedef struct PacketQueue {
    MyAVPacketList *first_pkt, *last_pkt;    //first_pkt Point to MyAVPacketList Is the head node of the node ,last_pkt Point to the tail node 
    int nb_packets; // How many are there at the moment AVPacket
    int size; // How much memory does the current linked list and the data in the linked list occupy 
    int64_t duration;
    int abort_request;
    int serial;
    SDL_mutex *mutex; // The mutex 
    SDL_cond *cond; //   Semaphore 
    MyAVPacketList *recycle_pkt; //MyAVPacketList Recycling linked list of , Avoid creating... Every time MyAVPacketList, Speed up 
    int recycle_count; // Reuse several MyAVPacketList
    int alloc_count;

    int is_buffer_indicator;
} PacketQueue;
static int packet_queue_init(PacketQueue *q)
{
    memset(q, 0, sizeof(PacketQueue));
    q->mutex = SDL_CreateMutex();
    if (!q->mutex) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    q->cond = SDL_CreateCond();
    if (!q->cond) {
        av_log(NULL, AV_LOG_FATAL, "SDL_CreateCond(): %s\n", SDL_GetError());
        return AVERROR(ENOMEM);
    }
    q->abort_request = 1;
    return 0;
}

Initialization is to initialize PacketQueue Members in are set to 0, Create a lock , Semaphore, etc
 

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);
}

packet_queue_start stay PacketQueue Put... First flush_pkt

What is? flush_pkt?
av_init_packet(&flush_pkt);
flush_pkt.data = (uint8_t *)&flush_pkt;

data Points to real data
flush_pkt.data = (uint8_t *)&flush_pkt; This explanation data Points to its own AvPacket

Let's take a look at packet_queue_put_private
 

static int packet_queue_put_private(PacketQueue *q, AVPacket *pkt)
{
    MyAVPacketList *pkt1;
	
	// Termination request , So long no longer PacketQueue Put the data in 
    if (q->abort_request)
       return -1;
	   
	//ffplay The source code of is to create a new node each time , and ijk Optimized , If recycle_pkt If there are available nodes, use , If not, allocate , also alloc_count Add 1,

#ifdef FFP_MERGE
    pkt1 = av_malloc(sizeof(MyAVPacketList)); 
#else
    pkt1 = q->recycle_pkt;
    if (pkt1) {
        q->recycle_pkt = pkt1->next;
        q->recycle_count++;
    } else {
        q->alloc_count++;
        pkt1 = av_malloc(sizeof(MyAVPacketList));
    }

#ifdef FFP_SHOW_PKT_RECYCLE
    int total_count = q->recycle_count + q->alloc_count;
    if (!(total_count % 50)) {
        av_log(ffp, AV_LOG_DEBUG, "pkt-recycle \t%d + \t%d = \t%d\n", q->recycle_count, q->alloc_count, total_count);
    }
#endif
#endif
    if (!pkt1)
        return -1;
    pkt1->pkt = *pkt;
    pkt1->next = NULL;
	// If it is currently flush_pkt, then serial++
    if (pkt == &flush_pkt)
        q->serial++;
    pkt1->serial = q->serial;
	
	
	 If it's the first node , So it's first_pkt assignment 
    if (!q->last_pkt)
        q->first_pkt = pkt1;
    else
        q->last_pkt->next = pkt1;
    q->last_pkt = pkt1;
    q->nb_packets++; // How many packages are there currently 
    q->size += pkt1->pkt.size + sizeof(*pkt1); // How much memory does the data in the current linked list occupy 

    q->duration += FFMAX(pkt1->pkt.duration, MIN_PKT_DURATION); // How long can the current linked list be played 

    /* XXX: should duplicate packet data in DV case */
    SDL_CondSignal(q->cond);
    return 0;
}

From the above, we can know that the final linked list should be like this 、


 

static void packet_queue_flush(PacketQueue *q)
{
    MyAVPacketList *pkt, *pkt1;

    SDL_LockMutex(q->mutex);
    for (pkt = q->first_pkt; pkt; pkt = pkt1) {
        pkt1 = pkt->next;
        av_packet_unref(&pkt->pkt);
#ifdef FFP_MERGE
        av_freep(&pkt);
#else
        pkt->next = q->recycle_pkt;
        q->recycle_pkt = pkt;
#endif
    }
    q->last_pkt = NULL;
    q->first_pkt = NULL;
    q->nb_packets = 0;
    q->size = 0;
    q->duration = 0;
    SDL_UnlockMutex(q->mutex);
}

// Looking at the code means that PacketQueue Medium first_pkt In the list AVPacket Release , And put MyAVPacketList Put the node in recycle_pkt, Other fields are set to 0


 

static void packet_queue_destroy(PacketQueue *q)
{
// hold PacketQueue Medium first_pkt In the list AVPacket Release , And put MyAVPacketList Put the node in recycle_pkt, Other fields are set to 0
    packet_queue_flush(q);

    SDL_LockMutex(q->mutex);
	// Release all recycle_pkt The nodes in the 
    while(q->recycle_pkt) {
        MyAVPacketList *pkt = q->recycle_pkt;
        if (pkt)
            q->recycle_pkt = pkt->next;
        av_freep(&pkt);
    }
    SDL_UnlockMutex(q->mutex);

    SDL_DestroyMutex(q->mutex);
    SDL_DestroyCond(q->cond);
}
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);
            q->duration -= FFMAX(pkt1->pkt.duration, MIN_PKT_DURATION);
            *pkt = pkt1->pkt;
            if (serial)
                *serial = pkt1->serial;
#ifdef FFP_MERGE
            av_free(pkt1);
#else
            pkt1->next = q->recycle_pkt;
            q->recycle_pkt = pkt1;
#endif
            ret = 1;
            break;
        } else if (!block) {
            ret = 0;
            break;
        } else {
            SDL_CondWait(q->cond, q->mutex);
        }
    }
    SDL_UnlockMutex(q->mutex);
    return ret;
}


//

static int packet_queue_get_or_buffering(FFPlayer *ffp, PacketQueue *q, AVPacket *pkt, int *serial, int *finished)
{
    assert(finished);
    if (!ffp->packet_buffering)
        return packet_queue_get(q, pkt, 1, serial);

    while (1) {
        int new_packet = packet_queue_get(q, pkt, 0, serial);
        if (new_packet < 0)
            return -1;
        else if (new_packet == 0) {
            if (q->is_buffer_indicator && !*finished)
                ffp_toggle_buffering(ffp, 1);
            new_packet = packet_queue_get(q, pkt, 1, serial);
            if (new_packet < 0)
                return -1;
        }

        if (*finished == *serial) {
            av_packet_unref(pkt);
            continue;
        }
        else
            break;
    }

    return 1;
}

// Take out first_pkt The node pointed to corresponds to AVPacket, And release the MyAVPacketList Put in recycle_pkt
 

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);
}

// Put a... In the queue AVPacket Of data by null The data of
 

原网站

版权声明
本文为[Original general breaking]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202280538435973.html