首先非常感谢先行者LiaoJunXiong (参考网页:https://blog.csdn.net/weixin_43549602/article/details/84571906)提供的使用gpac封装mp4的代码以及其他工程师基于此代码进行二次开发时所做的经验和问题的分享!
由于gpac源码过于庞大和复杂,如果完全看明白恐怕至少需要一个月的时间。先行者LiaoJunXiong把复杂问题大大简化了,基于gpac封装了一个简单得多的库,并且无私地分享了源码,使后来者大大受益,必须在此表示感谢。
但是美中不足地是:其一,源码工程中只是提供了库函数接口和源码实现,并未给出具体使用例程,需要后来者自行编写应用程序源代码;其二,当后来者自行加入应用程序源码后,如何与这个库以及gpac源码工程进行结合,编译出可执行程序(即给出Makefile),这一过程也没有;其三,虽然作者已经把include和lib文件夹一并上传了,但这2个文件夹的作用是什么,何时会用到,用到的时候具体该怎样使用,完全没有说明,而且lib中的库是基于gcc编译的还是基于交叉编译工具编译的,如果是交叉编译工具,是基于具体哪个交叉编译工具编译的,也没有相关的文档说明。这几点是令笔者非常不舒服的。
令笔者更为不理解地是,后来者们有很多人基于这个源码库构建了自己的项目并且已经完成了,那么你们好歹说一下自己具体是怎么做的,也让再后来的人别再走弯路了。如果让你们贴出源码可能涉及到隐私,强人所难,那么说个大概流程,给个自己在完成这一工作过程中遇到了那些难题、怎样解决的这种开发文档总不碍事吧。非常遗憾,也没有。
既然有遗憾,就要把它消除掉,不要留遗憾。笔者最近也开始走这个过程,与之前的人不同地是,我会把自己在这一块开发中所遇到的问题以及解决方法都记录下来,一来自己做个研发文档,二来供后来者参考。绝不能再像之前这种状态了!
一上来先把上边粗体标出的三个问题解决掉。
解决第1个问题,先给出应用例程源码main_app.c(很短、很简单,但当作参考足够了):
#ifdef __cplusplus
#if __cplusplus
extern "C"{
#endif
#endif /* End of #ifdef __cplusplus */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include "libmp4v2-write.h"
//主函数
int main(int argc, char *argv[])
{
int s32Ret;
int fd;
unsigned char buf[4096] = {0};
int data_len = 0;
fd = open("/mnt/nfs/main_app/mainapp_stream_chn1.h264", O_RDONLY);
if(fd < 0)
{
perror("open failed");
return -1;
}
AFMP4Handle mp4_Writer = MP4WriterInit();
MP4WriterCreateFile(mp4_Writer, (char *)"/mnt/nfs/main_app/test1.mp4", AF_MP4_VIDEO_H264, 1920, 1080, 25);
//AF_MP4Writer *pCMP4Writer = new AF_MP4Writer();
//pCMP4Writer->Create("/mnt/nfs/main_app/test1.mp4", AF_MP4_VIDEO_H264, 1920, 1080, 25);
while(1)
{
s32Ret = read(fd, buf, sizeof(buf)); //bc_get_frame_from_memory(bcCtx, &data, &dataLen);
if(s32Ret < 0)
{
printf("read failed\n");
close(fd);
return -1;
}
data_len = s32Ret;
printf("date_len is %d\n", data_len);
struct timeval timeNow;
gettimeofday(&timeNow, NULL);
long long nTimeStamp = timeNow.tv_sec * 1000 + timeNow.tv_usec / 1000;
MP4WriterWriteFile(mp4_Writer, buf, data_len, 1, nTimeStamp);
//pCMP4Writer->Write(buf, data_len, 1, nTimeStamp);
}
MP4WriterSaveFile(mp4_Writer);
//pCMP4Writer->Save();
MP4WriterExit(mp4_Writer);
//delete pCMP4Writer;
close(fd);
return s32Ret;
}
#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* End of #ifdef __cplusplus */
解决第2个问题,给出Makefile:
CC=arm-hisiv500-linux-gcc
CPP=arm-hisiv500-linux-g++
SRC_PATH:=$(shell pwd)
CFLAGS = -I. -I$(SRC_PATH)/include -DGPAC_HAVE_CONFIG_H
CPPFLAGS = -I. -I$(SRC_PATH)/include -DGPAC_HAVE_CONFIG_H
CFLAGS += -c -g -fPIC
CPPFLAGS += -c -g -fPIC
LDFLAGS=-L${SRC_PATH}/lib
LDFLAGS+=-lgpac
TARGET = main_app
CFILES := main_app.c
CPPFILES := libmp4v2-write.cpp
OBJS = $(CFILES:.c=.o) $(CPPFILES:.cpp=.o)
#OBJS=main_app.o libmp4v2-write.o
#SRCS := $(OBJS:.o=.c)
#SRCS := $(wildcard *.c)
#OBJS := $(patsubst %.c,%.o, $(SRCS))
all: $(TARGET)
$(TARGET): $(OBJS)
#$(CC) -o $@ $(OBJS) $(LINKFLAGS) $(LDFLAGS)
$(CPP) -o $@ $(OBJS) $(LINKFLAGS) $(LDFLAGS)
%.o:%.c
#$(CC) -o $@ $(CFLAGS) $<
$(CPP) -o $@ $(CFLAGS) $<
%.o:%.cpp
$(CPP) -o $@ $(CPPFLAGS) $<
clean:
echo "SRC_PATH is: ${SRC_PATH}"
rm -f $(OBJS) ${SRC_PATH}/$(TARGET)
这里要说明2点:
1. CC和CPP根据自己实际的情况进行修改,笔者用的是海思Hi3519v101,因此是arm-hisiv500-linux-XXX。
2. 一定要加入-DGPAC_HAVE_CONFIG_H选项,否则编译时会出现以下错误:
In file included from /home/aston/shiyan/include/gpac/setup.h:54:0,
from /home/aston/shiyan/include/gpac/tools.h:33,
from /home/aston/shiyan/include/gpac/isomedia.h:50,
from libmp4v2-write.cpp:4:
/home/aston/shiyan/include/gpac/configuration.h:163:2: error: #error "Unknown target platform used with static configuration file"
#error "Unknown target platform used with static configuration file"
^
Makefile:38: recipe for target 'libmp4v2-write.o' failed
make: *** [libmp4v2-write.o] Error 1
这个问题笔者刚开始遇到时,去百度搜索, 结果能搜到关键字,但点进去,进入到相关网页后内容又完全不相关了,不知是百度的问题还是CSDN的问题。最后笔者自行解决了这个问题,就是这一配置项。加入这一编译项之后还需要把gpac源码下的config.h拷贝到你自己的include能够找到的路径,这样才可以。
解决第3个问题,涉及到如何编译gpac,请参阅我不久前的帖子:https://blog.csdn.net/phmatthaus/article/details/106785506。
虽然帖子中是基于Hi3519交叉编译的,但实际上gcc编译更简单,只需要修改--cc=arm-hisiv500-linux-gcc --cxx=arm-hisiv500-linux-g++并且设置安装路径就好。
注:目前应用代码不能用于普通h264或h265文件的读写,特此声明。后续解决此问题后,会更新代码以及做修改说明。但其他文件以及方法依旧有效。