mirror of
https://gitee.com/openharmony/third_party_minimp4
synced 2024-12-04 02:51:52 +00:00
230 lines
6.8 KiB
C
230 lines
6.8 KiB
C
#define MINIMP4_IMPLEMENTATION
|
|
#ifdef _WIN32
|
|
#include <sys/types.h>
|
|
#include <stddef.h>
|
|
typedef size_t ssize_t;
|
|
#endif
|
|
#include "minimp4.h"
|
|
#define ENABLE_AUDIO 0
|
|
#if ENABLE_AUDIO
|
|
#include <fdk-aac/aacenc_lib.h>
|
|
#include <fdk-aac/aacdecoder_lib.h>
|
|
#define AUDIO_RATE 12000
|
|
#endif
|
|
|
|
#define VIDEO_FPS 30
|
|
|
|
static uint8_t *preload(const char *path, ssize_t *data_size)
|
|
{
|
|
FILE *file = fopen(path, "rb");
|
|
uint8_t *data;
|
|
*data_size = 0;
|
|
if (!file)
|
|
return 0;
|
|
if (fseek(file, 0, SEEK_END))
|
|
exit(1);
|
|
*data_size = (ssize_t)ftell(file);
|
|
if (*data_size < 0)
|
|
exit(1);
|
|
if (fseek(file, 0, SEEK_SET))
|
|
exit(1);
|
|
data = (unsigned char*)malloc(*data_size);
|
|
if (!data)
|
|
exit(1);
|
|
if ((ssize_t)fread(data, 1, *data_size, file) != *data_size)
|
|
exit(1);
|
|
fclose(file);
|
|
return data;
|
|
}
|
|
|
|
static ssize_t get_nal_size(uint8_t *buf, ssize_t size)
|
|
{
|
|
ssize_t pos = 3;
|
|
while ((size - pos) > 3)
|
|
{
|
|
if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 1)
|
|
return pos;
|
|
if (buf[pos] == 0 && buf[pos + 1] == 0 && buf[pos + 2] == 0 && buf[pos + 3] == 1)
|
|
return pos;
|
|
pos++;
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static int write_callback(int64_t offset, const void *buffer, size_t size, void *token)
|
|
{
|
|
FILE *f = (FILE*)token;
|
|
fseek(f, offset, SEEK_SET);
|
|
return fwrite(buffer, 1, size, f) != size;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
// check switches
|
|
int sequential_mode = 0;
|
|
int fragmentation_mode = 0;
|
|
int i;
|
|
for(i = 1; i < argc; i++)
|
|
{
|
|
if (argv[i][0] != '-')
|
|
break;
|
|
switch (argv[i][1])
|
|
{
|
|
case 's': sequential_mode = 1; break;
|
|
case 'f': fragmentation_mode = 1; break;
|
|
default:
|
|
printf("error: unrecognized option\n");
|
|
return 1;
|
|
}
|
|
}
|
|
if (argc <= (i + 1))
|
|
{
|
|
printf("Usage: minimp4 [options] in.h264 out.mp4\n"
|
|
"Options:\n"
|
|
" -s - enable sequential mode (no seek required for writing)\n"
|
|
" -f - enable fragmentation mode (aka fMP4)\n");
|
|
return 0;
|
|
}
|
|
ssize_t h264_size;
|
|
uint8_t *alloc_buf;
|
|
uint8_t *buf_h264 = alloc_buf = preload(argv[i], &h264_size);
|
|
if (!buf_h264)
|
|
{
|
|
printf("error: can't open h264 file\n");
|
|
return 0;
|
|
}
|
|
|
|
FILE *fout = fopen(argv[i + 1], "wb");
|
|
if (!fout)
|
|
{
|
|
printf("error: can't open output file\n");
|
|
return 0;
|
|
}
|
|
int is_hevc = (0 != strstr(argv[1], "265")) || (0 != strstr(argv[i], "hevc"));
|
|
|
|
MP4E_mux_t *mux;
|
|
mp4_h26x_writer_t mp4wr;
|
|
mux = MP4E_open(sequential_mode, fragmentation_mode, fout, write_callback);
|
|
if (MP4E_STATUS_OK != mp4_h26x_write_init(&mp4wr, mux, 352, 288, is_hevc))
|
|
{
|
|
printf("error: mp4_h26x_write_init failed\n");
|
|
return 0;
|
|
}
|
|
|
|
#if ENABLE_AUDIO
|
|
ssize_t pcm_size;
|
|
int16_t *alloc_pcm;
|
|
int16_t *buf_pcm = alloc_pcm = (int16_t *)preload("stream.pcm", &pcm_size);
|
|
if (!buf_pcm)
|
|
{
|
|
printf("error: can't open pcm file\n");
|
|
return 0;
|
|
}
|
|
uint32_t sample = 0, total_samples = pcm_size/2;
|
|
uint64_t ts = 0, ats = 0;
|
|
HANDLE_AACENCODER aacenc;
|
|
AACENC_InfoStruct info;
|
|
aacEncOpen(&aacenc, 0, 0);
|
|
aacEncoder_SetParam(aacenc, AACENC_TRANSMUX, 0);
|
|
aacEncoder_SetParam(aacenc, AACENC_AFTERBURNER, 1);
|
|
aacEncoder_SetParam(aacenc, AACENC_BITRATE, 64000);
|
|
aacEncoder_SetParam(aacenc, AACENC_SAMPLERATE, AUDIO_RATE);
|
|
aacEncoder_SetParam(aacenc, AACENC_CHANNELMODE, 1);
|
|
aacEncEncode(aacenc, NULL, NULL, NULL, NULL);
|
|
aacEncInfo(aacenc, &info);
|
|
|
|
MP4E_track_t tr;
|
|
tr.track_media_kind = e_audio;
|
|
tr.language[0] = 'u';
|
|
tr.language[1] = 'n';
|
|
tr.language[2] = 'd';
|
|
tr.language[3] = 0;
|
|
tr.object_type_indication = MP4_OBJECT_TYPE_AUDIO_ISO_IEC_14496_3;
|
|
tr.time_scale = 90000;
|
|
tr.default_duration = 0;
|
|
tr.u.a.channelcount = 1;
|
|
int audio_track_id = MP4E_add_track(mux, &tr);
|
|
MP4E_set_dsi(mux, audio_track_id, info.confBuf, info.confSize);
|
|
#endif
|
|
while (h264_size > 0)
|
|
{
|
|
ssize_t nal_size = get_nal_size(buf_h264, h264_size);
|
|
if (nal_size < 4)
|
|
{
|
|
buf_h264 += 1;
|
|
h264_size -= 1;
|
|
continue;
|
|
}
|
|
/*int startcode_size = 4;
|
|
if (buf_h264[0] == 0 && buf_h264[1] == 0 && buf_h264[2] == 1)
|
|
startcode_size = 3;
|
|
int nal_type = buf_h264[startcode_size] & 31;
|
|
int is_intra = (nal_type == 5);
|
|
printf("nal size=%ld, nal_type=%d\n", nal_size, nal_type);*/
|
|
|
|
if (MP4E_STATUS_OK != mp4_h26x_write_nal(&mp4wr, buf_h264, nal_size, 90000/VIDEO_FPS))
|
|
{
|
|
printf("error: mp4_h26x_write_nal failed\n");
|
|
return 0;
|
|
}
|
|
buf_h264 += nal_size;
|
|
h264_size -= nal_size;
|
|
|
|
#if ENABLE_AUDIO
|
|
ts += 90000/VIDEO_FPS;
|
|
while (ats < ts)
|
|
{
|
|
AACENC_BufDesc in_buf, out_buf;
|
|
AACENC_InArgs in_args;
|
|
AACENC_OutArgs out_args;
|
|
uint8_t buf[2048];
|
|
if (total_samples < 1024)
|
|
{
|
|
buf_pcm = alloc_pcm;
|
|
total_samples = pcm_size/2;
|
|
}
|
|
in_args.numInSamples = 1024;
|
|
void *in_ptr = buf_pcm, *out_ptr = buf;
|
|
int in_size = 2*in_args.numInSamples;
|
|
int in_element_size = 2;
|
|
int in_identifier = IN_AUDIO_DATA;
|
|
int out_size = sizeof(buf);
|
|
int out_identifier = OUT_BITSTREAM_DATA;
|
|
int out_element_size = 1;
|
|
|
|
in_buf.numBufs = 1;
|
|
in_buf.bufs = &in_ptr;
|
|
in_buf.bufferIdentifiers = &in_identifier;
|
|
in_buf.bufSizes = &in_size;
|
|
in_buf.bufElSizes = &in_element_size;
|
|
out_buf.numBufs = 1;
|
|
out_buf.bufs = &out_ptr;
|
|
out_buf.bufferIdentifiers = &out_identifier;
|
|
out_buf.bufSizes = &out_size;
|
|
out_buf.bufElSizes = &out_element_size;
|
|
|
|
if (AACENC_OK != aacEncEncode(aacenc, &in_buf, &out_buf, &in_args, &out_args))
|
|
{
|
|
printf("error: aac encode fail\n");
|
|
exit(1);
|
|
}
|
|
sample += in_args.numInSamples;
|
|
buf_pcm += in_args.numInSamples;
|
|
total_samples -= in_args.numInSamples;
|
|
ats = (uint64_t)sample*90000/AUDIO_RATE;
|
|
|
|
if (MP4E_STATUS_OK != MP4E_put_sample(mux, audio_track_id, buf, out_args.numOutBytes, 1024*90000/AUDIO_RATE, MP4E_SAMPLE_RANDOM_ACCESS))
|
|
{
|
|
printf("error: MP4E_put_sample failed\n");
|
|
return 0;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
if (alloc_buf)
|
|
free(alloc_buf);
|
|
MP4E_close(mux);
|
|
if (fout)
|
|
fclose(fout);
|
|
}
|