Разработка приложения Ingenic T31 8: Получение потока кода JEPG
Разработка приложения Ingenic T31 8: Получение потока кода JEPG

1. Получите структуру потока кода JEPG.

Имя файла sample-Encoder-jpeg.c

Основной поток кода для получения изображений выглядит следующим образом:

T31, возьми блок-схему системы потоков JPEG.
T31, возьми блок-схему системы потоков JPEG.

Прежде всего, большинство функций нашего файла зависят от двух файлов sample-common.h и sample-common.c. Большинство демонстрационных программ разрабатываются путем вызова базовой библиотеки, предоставляемой common.c.

PS: Большинство основных библиотечных API-функций Ingenic T31 имеют формат IMP_XXX_XXX, например

IMP_OSD_SetPoolSize

IMP_ISP_AddSensor

и т. д.

1.1: Инициализация системных параметров T31: sample_system_init

Язык кода:javascript
копировать
int sample_system_init()
{
	int ret = 0;

	IMP_OSD_SetPoolSize(512*1024);
	memset(&sensor_info, 0, sizeof(IMPSensorInfo));
	memcpy(sensor_info.name, SENSOR_NAME, sizeof(SENSOR_NAME));
	sensor_info.cbus_type = SENSOR_CUBS_TYPE;
	memcpy(sensor_info.i2c.type, SENSOR_NAME, sizeof(SENSOR_NAME));
	sensor_info.i2c.addr = SENSOR_I2C_ADDR;

	IMP_LOG_DBG(TAG, "sample_system_init start\n");

	ret = IMP_ISP_Open();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to open ISP\n");
		return -1;
	}

	ret = IMP_ISP_AddSensor(&sensor_info);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to AddSensor\n");
		return -1;
	}

	ret = IMP_ISP_EnableSensor();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to EnableSensor\n");
		return -1;
	}

	ret = IMP_System_Init();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "IMP_System_Init failed\n");
		return -1;
	}

	/* enable turning, to debug graphics */
	ret = IMP_ISP_EnableTuning();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "IMP_ISP_EnableTuning failed\n");
		return -1;
	}
    IMP_ISP_Tuning_SetContrast(128);
    IMP_ISP_Tuning_SetSharpness(128);
    IMP_ISP_Tuning_SetSaturation(128);
    IMP_ISP_Tuning_SetBrightness(128);
#if 1
    ret = IMP_ISP_Tuning_SetISPRunningMode(IMPISP_RUNNING_MODE_DAY);
    if (ret < 0){
        IMP_LOG_ERR(TAG, "failed to set running mode\n");
        return -1;
    }
#endif
#if 0
    ret = IMP_ISP_Tuning_SetSensorFPS(SENSOR_FRAME_RATE_NUM, SENSOR_FRAME_RATE_DEN);
    if (ret < 0){
        IMP_LOG_ERR(TAG, "failed to set sensor fps\n");
        return -1;
    }
#endif
	IMP_LOG_DBG(TAG, "ImpSystemInit success\n");

	return 0;
}

В основном это объясняет эту функцию API: IMP_ISP_AddSensor.

Эта функция является функцией системы для загрузки датчиков. Наша программа T31 может загружать не только один датчик, но и множество различных датчиков. Среди них тестовая машина, которую я купил на Taobao, использует датчик типа SENSOR_SC5235.

На рисунке ниже мы можем наблюдать информацию о параметрах, передаваемую в основном в SDK через некоторые макроопределения датчика.

Датчиком по умолчанию в библиотеке SDK является jxf23, поэтому, если мы хотим вызвать поток кода JPEG для работы, нам нужно изменить код, прежде чем мы сможем его использовать.

конфигурация датчика sc5235
конфигурация датчика sc5235

1.2: Инициализация источника видео: sample_framesource_init

Ключевые параметры функции IMP_FrameSource_CreateChn

Согласно тому, что мы говорили в предыдущей главе, если вам нужно использовать API-интерфейсы, связанные с видео, вы должны инициализировать источник видео. Шаги для инициализации источника видео:

Инициализация процесса инициализации

1. Создайте канал

2. Настройте каналы

3. Включить канал

Следующая функция в основном выполняет эти два шага:

Создайте каналы и установите свойства каналов.

Язык кода:javascript
копировать
основной поток:
	struct chn_conf chn[FS_CHN_NUM] = {
	{
		.index = CH0_INDEX,
		.enable = CHN0_EN,
    .payloadType = IMP_ENC_PROFILE_HEVC_MAIN,
		.fs_chn_attr = {
			.pixFmt = PIX_FMT_NV12,
			.outFrmRateNum = SENSOR_FRAME_RATE_NUM,
			.outFrmRateDen = SENSOR_FRAME_RATE_DEN,
			.nrVBs = 2,
			.type = FS_PHY_CHANNEL,

			.scaler.enable = 0,

			.crop.enable = CROP_EN,
			.crop.top = 0,
			.crop.left = 0,
			.crop.width = SENSOR_WIDTH,
			.crop.height = SENSOR_HEIGHT,

			.picWidth = SENSOR_WIDTH,
			.picHeight = SENSOR_HEIGHT,
		   },
		.framesource_chn = { DEV_ID_FS, CH0_INDEX, 0},
		.imp_encoder = { DEV_ID_ENC, CH0_INDEX, 0},
	},

Язык кода:javascript
копировать
int sample_framesource_init()
{
	int i, ret;

	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			IMP_LOG_INFO(TAG,"sample_framesource_init i = %d\n",i);
			ret = IMP_FrameSource_CreateChn(chn[i].index, &chn[i].fs_chn_attr);
			if(ret < 0){
				IMP_LOG_ERR(TAG, "IMP_FrameSource_CreateChn(chn%d) error !\n", chn[i].index);
				return -1;
			}

			ret = IMP_FrameSource_SetChnAttr(chn[i].index, &chn[i].fs_chn_attr);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_FrameSource_SetChnAttr(chn%d) error !\n",  chn[i].index);
				return -1;
			}
		}
	}
	return 0;
}

1.3: Установите тип кодирования IMP_Encoder_CreateGroup

Здесь мы задаем, сколько групп данных необходимо для кодирования, и концепцию настройки групп кодирования: об этом мы также говорили на предыдущем уроке;

Группа кодирования может не только кодировать данные кодового потока H264, но также кодировать данные JPEG.

Язык кода:javascript
копировать
	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			ret = IMP_Encoder_CreateGroup(chn[i].index);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_Encoder_CreateGroup(%d) error !\n", i);
				return -1;
			}
		}
	}

1.4: Инициализация параметра кодирования sample_jpeg_init

Самый важный параметр — это функция: IMP_Encoder_SetDefaultParam.

Установите параметры кодировки по умолчанию: IMP_ENC_PROFILE_JPEG.

Язык кода:javascript
копировать
int sample_jpeg_init()
{
	int i, ret;
	IMPEncoderChnAttr channel_attr;
	IMPFSChnAttr *imp_chn_attr_tmp;

	for (i = 0; i <  FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			imp_chn_attr_tmp = &chn[i].fs_chn_attr;
			memset(&channel_attr, 0, sizeof(IMPEncoderChnAttr));
			ret = IMP_Encoder_SetDefaultParam(&channel_attr, IMP_ENC_PROFILE_JPEG, IMP_ENC_RC_MODE_FIXQP,
					imp_chn_attr_tmp->picWidth, imp_chn_attr_tmp->picHeight,
					imp_chn_attr_tmp->outFrmRateNum, imp_chn_attr_tmp->outFrmRateDen, 0, 0, 25, 0);
			/* Create Channel */
			ret = IMP_Encoder_CreateChn(4 + chn[i].index, &channel_attr);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_Encoder_CreateChn(%d) error: %d\n",
							chn[i].index, ret);
				return -1;
			}
			/* Resigter Channel */
			ret = IMP_Encoder_RegisterChn(i, 4 + chn[i].index);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_Encoder_RegisterChn(0, %d) error: %d\n",
							chn[i].index, ret);
				return -1;
			}
		}
	}
	return 0;
}

1.5: Функция привязки системы IMP_System_Bind

Основной шаг — связать вместе инициализированный источник видео и кодировщик.

Язык кода:javascript
копировать
	/* Step.4 Bind */
	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			ret = IMP_System_Bind(&chn[i].framesource_chn, &chn[i].imp_encoder);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "Bind FrameSource channel%d and Encoder failed\n",i);
				return -1;
			}
		}
	}

1.6: Включить данные источника видео sample_framesource_streamon

Эта часть предназначена для того, чтобы сначала создать источник видео, снова настроить источник видео, а затем включить источник видео, как упоминалось ранее.

Язык кода:javascript
копировать
int sample_framesource_streamon()
{
	int ret = 0, i = 0;
	/* Enable channels */
	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			IMP_LOG_INFO(TAG,"sample_framesource_streamon i = %d\n",i);
			ret = IMP_FrameSource_EnableChn(chn[i].index);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_FrameSource_EnableChn(%d) error: %d\n", ret, chn[i].index);
				return -1;
			}
		}
	}
	return 0;
}

2. Получите функцию потока кода JPEG.

2.1: sample_get_jpeg_snap получает поток кода скриншота.

После того, как мы выполнили все действия, которые мы инициализировали ранее, включая инициализацию данных источника видео и привязку нашего метода кодирования, метод кодирования, который мы здесь связали, — это режим кодирования JPEG. Далее мы получим данные JPEG.

IMP_Encoder_StartRecvPic: открыть канал кодирования для получения изображений.

IMP_Encoder_PollingStream: кэш потока опроса, тайм-аут, который мы установили, составляет 1 секунду.

IMP_Encoder_GetStream:

Для кодовых потоков типов H264 и H265 один вызов успешно получает один кадр кодового потока. Этот кадр кодового потока может содержать несколько пакетов.

Для кодового потока типа JPEG один вызов успешно получает кодовый поток одного кадра. Этот кодовый поток кадра содержит только один пакет. Этот кадр содержит полную информацию файла изображения JPEG.

Наконец, мы используем эту функцию для обратного вызова данных структуры и сохранения их на нашей TF-карте, чтобы завершить этапы получения потока кода JPEG.

Язык кода:javascript
копировать
/**
 * Определите структуру типа потока кадров кодирования
 */
typedef struct {
	uint32_t		  phyAddr;          /**< Физический адрес потока кода кадра */
	uint32_t		  virAddr;          /**< Виртуальный адрес пакета потока кадров */
	uint32_t		  streamSize;       /**< virAddr соответствует размеру выделенного адресного пространства. */
	IMPEncoderPack  *pack;				/**< Структура пакета потока кадров */
	uint32_t        packCount;			/**< Количество всех пакетов в одном кадре кодового потока */
	uint32_t        seq;				/**< Порядковый номер потока закодированных кадров */
	union
	{
		IMPEncoderStreamInfo streamInfo;
		IMPEncoderJpegInfo jpegInfo;
	};
} IMPEncoderStream;
Язык кода:javascript
копировать
static int save_stream(int fd, IMPEncoderStream *stream)
{
	int ret, i, nr_pack = stream->packCount;

  //IMP_LOG_DBG(TAG, "----------packCount=%d, stream->seq=%u start----------\n", stream->packCount, stream->seq);
	for (i = 0; i < nr_pack; i++) {
    //IMP_LOG_DBG(TAG, "[%d]:%10u,%10lld,%10u,%10u,%10u\n", i, stream->pack[i].length, stream->pack[i].timestamp, stream->pack[i].frameEnd, *((uint32_t *)(&stream->pack[i].nalType)), stream->pack[i].sliceType);
		IMPEncoderPack *pack = &stream->pack[i];
		if(pack->length){
			uint32_t remSize = stream->streamSize - pack->offset;
			if(remSize < pack->length){
				ret = write(fd, (void *)(stream->virAddr + pack->offset), remSize);
				if (ret != remSize) {
					IMP_LOG_ERR(TAG, "stream write ret(%d) != pack[%d].remSize(%d) error:%s\n", ret, i, remSize, strerror(errno));
					return -1;
				}
				ret = write(fd, (void *)stream->virAddr, pack->length - remSize);
				if (ret != (pack->length - remSize)) {
					IMP_LOG_ERR(TAG, "stream write ret(%d) != pack[%d].(length-remSize)(%d) error:%s\n", ret, i, (pack->length - remSize), strerror(errno));
					return -1;
				}
			}else {
				ret = write(fd, (void *)(stream->virAddr + pack->offset), pack->length);
				if (ret != pack->length) {
					IMP_LOG_ERR(TAG, "stream write ret(%d) != pack[%d].length(%d) error:%s\n", ret, i, pack->length, strerror(errno));
					return -1;
				}
			}
		}
	}
  //IMP_LOG_DBG(TAG, "----------packCount=%d, stream->seq=%u end----------\n", stream->packCount, stream->seq);
	return 0;
}

2.2: Освободите данные кодового потока, которые мы получаем из канала JPEG.

IMP_Encoder_ReleaseStream

После того, как пользователь получит кодовый поток, он должен вовремя освободить кэш полученного кодового потока, иначе буфер кодового потока может переполниться и повлиять на кодирование кодера.

Этот интерфейс должен быть связан с IMP_Encoder_GetStream.

IMP_Encoder_StopRecvPic: прекратить кодирование каналов, получающих изображения.

2.3: Выход из процесса кодирования

sample_framesource_streamoff

Язык кода:javascript
копировать
int sample_framesource_streamoff()
{
	int ret = 0, i = 0;
	/* Enable channels */
	for (i = 0; i < FS_CHN_NUM; i++) {
		if (chn[i].enable){
			ret = IMP_FrameSource_DisableChn(chn[i].index);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_FrameSource_DisableChn(%d) error: %d\n", ret, chn[i].index);
				return -1;
			}
		}
	}
	return 0;
}

IMP_System_UnBind

Отменив привязку, мы просто связали поток, чтобы получить изображение. С этой точки зрения мы получаем только один кадр данных в основном потоке или подпотоке, поэтому в экспериментальной ситуации демо-версии также получены два изображения, одно из которых — изображение. основного потока и одно изображение подпотока.

Язык кода:javascript
копировать
int sample_jpeg_exit(void)
{
	int ret = 0, i = 0, chnNum = 0;
	IMPEncoderChnStat chn_stat;

	for (i = 0; i <  FS_CHN_NUM; i++) {
		if (chn[i].enable) {
			chnNum = 4 + chn[i].index;
			memset(&chn_stat, 0, sizeof(IMPEncoderChnStat));
			ret = IMP_Encoder_Query(chnNum, &chn_stat);
			if (ret < 0) {
				IMP_LOG_ERR(TAG, "IMP_Encoder_Query(%d) error: %d\n", chnNum, ret);
				return -1;
			}

			if (chn_stat.registered) {
				ret = IMP_Encoder_UnRegisterChn(chnNum);
				if (ret < 0) {
					IMP_LOG_ERR(TAG, "IMP_Encoder_UnRegisterChn(%d) error: %d\n", chnNum, ret);
					return -1;
				}

				ret = IMP_Encoder_DestroyChn(chnNum);
				if (ret < 0) {
					IMP_LOG_ERR(TAG, "IMP_Encoder_DestroyChn(%d) error: %d\n", chnNum, ret);
					return -1;
				}
			}
		}
	}

	return 0;
}

2.4: Выйдите из инициализации системы и дайте системе завершить работу.

sample_system_exit

Язык кода:javascript
копировать
int sample_system_exit()
{
	int ret = 0;

	IMP_LOG_DBG(TAG, "sample_system_exit start\n");


	IMP_System_Exit();

	ret = IMP_ISP_DisableSensor();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to EnableSensor\n");
		return -1;
	}

	ret = IMP_ISP_DelSensor(&sensor_info);
	if(ret < 0){
		IMP_LOG_ERR(TAG, "failed to AddSensor\n");
		return -1;
	}

	ret = IMP_ISP_DisableTuning();
	if(ret < 0){
		IMP_LOG_ERR(TAG, "IMP_ISP_DisableTuning failed\n");
		return -1;
	}

	if(IMP_ISP_Close()){
		IMP_LOG_ERR(TAG, "failed to open ISP\n");
		return -1;
	}

	IMP_LOG_DBG(TAG, " sample_system_exit success\n");

	return 0;
}

3. Результаты эксперимента: получите две картинки.

Здесь я намеренно добавил часть журнала в демо-версию, чтобы облегчить сравнение с ситуацией, о которой я упоминал выше. Реальная программа работает в соответствии с упомянутым мной процессом.

Процесс получения 2 фотографий
Процесс получения 2 фотографий

Полученное разрешение также соответствует заданному нами разрешению. Можно судить, что весь процесс завершился идеально.

sdk
boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose