Files
luban-lite-t3e-pro/packages/artinchip/mpp/ve/decoder/packet_manager.c
刘可亮 7bbc029dae v1.0.0
2023-08-30 16:21:18 +08:00

370 lines
9.2 KiB
C

/*
* Copyright (C) 2020-2022 Artinchip Technology Co. Ltd
*
* author: <qi.xu@artinchip.com>
* Desc: packet (video bitstream container) manager
*/
#define LOG_TAG "packet_manager"
#include <string.h>
//#include <pthread.h>
#include "mpp_dec_type.h"
#include "mpp_mem.h"
#include "ve_buffer.h"
#include "packet_manager.h"
#include "mpp_list.h"
#include "mpp_log.h"
#include "aic_core.h"
struct packet_impl {
struct packet pkt;
size_t pos_offset;
struct mpp_list list;
};
struct packet_manager {
int limit_count;
int packet_count;
//pthread_mutex_t lock;
aicos_mutex_t lock;
struct mpp_list empty_list;
struct mpp_list ready_list;
int empty_num;
int ready_num;
struct packet_impl *packet_node;
struct ve_buffer *mpp_buf;
struct ve_buffer_allocator *ve_buf_handle;
unsigned int buffer_phy; // phy start addr of stream buffer
unsigned char *buffer_start; // virtual start addr of stream buffer
unsigned char *buffer_end; // virtual end addr of stream buffer
int buffer_size; // total size of stream buffer
int write_offset;
int read_offset;
int available_size;
};
struct packet_manager *pm_create(struct packet_manager_init_cfg *cfg)
{
struct packet_manager_init_cfg *init_cfg = cfg;
struct packet_manager *pm;
struct packet_impl *pkt_impl;
int i;
logd("create packet manager");
if (!init_cfg || !init_cfg->ve_buf_handle || init_cfg->packet_count <= 0 || init_cfg->buffer_size <= 0)
return NULL;
pm = (struct packet_manager *)mpp_alloc(sizeof(struct packet_manager));
if (!pm)
return NULL;
pm->empty_num = init_cfg->packet_count;
pm->ready_num = 0;
pm->packet_count = init_cfg->packet_count;
pm->packet_node = (struct packet_impl *)mpp_alloc(pm->packet_count * sizeof(struct packet_impl));
if (!pm->packet_node) {
loge("alloc %d count packet failed!", pm->packet_count);
mpp_free(pm);
return NULL;
}
memset(pm->packet_node, 0, pm->packet_count * sizeof(struct packet_impl));
pm->ve_buf_handle = init_cfg->ve_buf_handle;
pm->buffer_size = init_cfg->buffer_size;
pm->mpp_buf = ve_buffer_alloc(pm->ve_buf_handle, pm->buffer_size, ALLOC_NEED_VIR_ADDR);
if (!pm->mpp_buf) {
loge("alloc mpp buffer %d failed!", pm->buffer_size);
mpp_free(pm->packet_node);
mpp_free(pm);
}
logd("packet manager create %d count packet, buffer size %d", pm->packet_count, pm->buffer_size);
pm->buffer_start = pm->mpp_buf->vir_addr;
pm->buffer_end = pm->mpp_buf->vir_addr + pm->mpp_buf->size - 1;
pm->buffer_size = pm->mpp_buf->size;
pm->buffer_phy = pm->mpp_buf->phy_addr;
pm->read_offset = 0;
pm->write_offset = 0;
pm->available_size = pm->mpp_buf->size;
//pthread_mutex_init(&pm->lock, NULL);
pm->lock = aicos_mutex_create();
mpp_list_init(&pm->empty_list);
mpp_list_init(&pm->ready_list);
pkt_impl = pm->packet_node;
for (i = 0; i < pm->packet_count; i++) {
mpp_list_init(&pkt_impl->list);
mpp_list_add_tail(&pkt_impl->list, &pm->empty_list);
pkt_impl++;
}
logd("create packet manager successful! (%p)", pm);
return pm;
}
int pm_destroy(struct packet_manager *pm)
{
logd("destroy packet manager");
if (!pm)
return -1;
//pthread_mutex_destroy(&pm->lock);
aicos_mutex_delete(pm->lock);
if (pm->mpp_buf) {
ve_buffer_free(pm->ve_buf_handle, pm->mpp_buf);
}
if (pm->packet_node)
mpp_free(pm->packet_node);
if (pm)
mpp_free(pm);
return 0;
}
int pm_dequeue_empty_packet(struct packet_manager *pm, struct mpp_packet *packet, int size)
{
struct packet_impl *pkt_impl;
int left_size; // remain size in end of stream buffer
//int write_offset = 0;
if (!pm || !packet || size <= 0)
return -1;
logd("packet manager dequeue empty mpp packet, pm: %p, packet: %p, size: %d", pm, packet, size);
//pthread_mutex_lock(&pm->lock);
aicos_mutex_take(pm->lock,AICOS_WAIT_FOREVER);
left_size = pm->buffer_size - pm->write_offset;
if (pm->available_size < size) {
logw("packet manager dequeue mpp packet size %d > available size %d", size, pm->available_size);
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return -1;
}
if (pm->write_offset >= pm->read_offset) {
if (left_size < size && pm->read_offset < size) {
logw("packet manager dequeue mpp packet size(%d) failed, read offset %d write offset %d", size,
pm->read_offset, pm->write_offset);
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return -1;
}
}
pkt_impl = mpp_list_first_entry_or_null(&pm->empty_list, struct packet_impl, list);
if(!pkt_impl) {
logw("packet manager dequeue mpp packet failed!");
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return -1;
}
pkt_impl->pkt.size = size;
pkt_impl->pkt.phy_offset = pm->write_offset;
pkt_impl->pkt.phy_size = pm->buffer_size;
pkt_impl->pkt.phy_base = pm->buffer_phy;
pkt_impl->pkt.data = pm->buffer_start + pm->write_offset;
pkt_impl->pos_offset = 0;
if (pm->write_offset >= pm->read_offset) {
if (left_size >= size) {
//* if left_size is enough to store this packet
pm->write_offset += size;
pm->available_size -= size;
if (pm->write_offset == pm->buffer_size)
pm->write_offset = 0;
} else if (pm->read_offset >= size) {
logw("left_size: %d, size: %d", left_size, size);
//* if left_size is not enough to store this packet,
//* we store this packet from the start of stream buffer
pm->write_offset = size;
pm->available_size -= (size + left_size);
pkt_impl->pos_offset = left_size;
pkt_impl->pkt.data = pm->buffer_start;
pkt_impl->pkt.phy_offset = 0;
} else {
// left_size is not enough to store this packet,
// and there is no buffer in start of stream buffer
logw("packet manager dequeue mpp packet failed!");
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return -1;
}
} else {
pm->write_offset += size;
pm->available_size -= size;
}
logw("get empty packet phy_offset: %d, size: %d", pm->write_offset, size);
packet->data = pkt_impl->pkt.data;
packet->size = pkt_impl->pkt.size;
pm->empty_num --;
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return 0;
}
int pm_enqueue_ready_packet(struct packet_manager *pm, struct mpp_packet *packet)
{
struct packet_impl *pkt_impl;
size_t left_offset;
logd("packet manager enqueue ready mpp packet");
if (!pm || !packet)
return -1;
//pthread_mutex_lock(&pm->lock);
aicos_mutex_take(pm->lock,AICOS_WAIT_FOREVER);
pkt_impl = mpp_list_first_entry_or_null(&pm->empty_list, struct packet_impl, list);
if(!pkt_impl) {
logw("packet manager enqueue ready mpp packet failed!");
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return -1;
}
if (pkt_impl->pkt.data != packet->data || pkt_impl->pkt.size < packet->size) {
logw("packet manager enqueue ready mpp packet check failed!");
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return -1;
}
if (pkt_impl->pkt.size > packet->size) {
left_offset = pkt_impl->pkt.size - packet->size;
if (pm->write_offset == 0) {
pm->write_offset = pm->buffer_size - left_offset;
pm->available_size += left_offset;
} else {
pm->write_offset -= left_offset;
pm->available_size += left_offset;
}
}
pkt_impl->pkt.size = packet->size;
pkt_impl->pkt.pts = packet->pts;
pkt_impl->pkt.flag = packet->flag;
mpp_list_del_init(&pkt_impl->list);
mpp_list_add_tail(&pkt_impl->list, &pm->ready_list);
pm->ready_num++;
ve_buffer_sync_range(pm->mpp_buf, pkt_impl->pkt.data, pkt_impl->pkt.size, CACHE_CLEAN);
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return 0;
}
int pm_reclaim_ready_packet(struct packet_manager *pm, struct packet *packet)
{
logd("packet manager return ready mpp packet");
if (!pm || !packet)
return -1;
//pthread_mutex_lock(&pm->lock);
aicos_mutex_take(pm->lock,AICOS_WAIT_FOREVER);
pm->ready_num++;
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return 0;
}
struct packet *pm_dequeue_ready_packet(struct packet_manager *pm)
{
struct packet_impl *pkt_impl;
logd("packet manager dequeue ready packet");
if (!pm)
return NULL;
//pthread_mutex_lock(&pm->lock);
aicos_mutex_take(pm->lock,AICOS_WAIT_FOREVER);
pkt_impl = mpp_list_first_entry_or_null(&pm->ready_list, struct packet_impl, list);
if(!pkt_impl) {
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return NULL;
}
pm->ready_num--;
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return (struct packet *)pkt_impl;
}
int pm_enqueue_empty_packet(struct packet_manager *pm, struct packet *packet)
{
struct packet_impl *pkt_impl = (struct packet_impl *)packet;
size_t read_offset;
logd("packet manager enqueue empty packet");
if (!pm || !pkt_impl)
return -1;
//pthread_mutex_lock(&pm->lock);
aicos_mutex_take(pm->lock,AICOS_WAIT_FOREVER);
mpp_list_del_init(&pkt_impl->list);
mpp_list_add_tail(&pkt_impl->list, &pm->empty_list);
read_offset = pm->read_offset + pkt_impl->pos_offset + pkt_impl->pkt.size;
if (read_offset >= pm->buffer_size)
read_offset -= pm->buffer_size;
pm->read_offset = read_offset;
pm->available_size += pkt_impl->pos_offset + pkt_impl->pkt.size;
pm->empty_num++;
//pthread_mutex_unlock(&pm->lock);
aicos_mutex_give(pm->lock);
return 0;
}
int pm_get_empty_packet_num(struct packet_manager *pm)
{
return pm->empty_num;
}
int pm_get_ready_packet_num(struct packet_manager *pm)
{
return pm->ready_num;
}