#include "mp4-writer.h" #include "mov-format.h" #include "mpeg4-hevc.h" #include "mpeg4-avc.h" #include #include #include #include #define MOV_WRITER_H265_FMP4 0 extern "C" const struct mov_buffer_t* mov_file_buffer(void); #define H265_NAL(v) ((v >> 1) & 0x3F) static uint8_t s_buffer[2 * 1024 * 1024]; static uint8_t s_extra_data[64 * 1024]; struct mov_h265_test_t { mp4_writer_t* mov; struct mpeg4_hevc_t hevc; int track; int width; int height; uint32_t pts, dts; const uint8_t* ptr; uint8_t buf[1024 * 64]; int bytes; int vcl; }; static uint8_t* file_read(const char* file, long* size) { FILE* fp = fopen(file, "rb"); if (fp) { fseek(fp, 0, SEEK_END); *size = ftell(fp); fseek(fp, 0, SEEK_SET); uint8_t* ptr = (uint8_t*)malloc(*size); fread(ptr, 1, *size, fp); fclose(fp); return ptr; } return NULL; } static int h265_write(struct mov_h265_test_t* ctx, const void* data, int bytes) { int vcl = 0; int update = 0; int n = h265_annexbtomp4(&ctx->hevc, data, bytes, s_buffer, sizeof(s_buffer), &vcl, &update); if (ctx->track < 0) { if (ctx->hevc.numOfArrays < 1) { //ctx->ptr = end; return -2; // waiting for vps/sps/pps } int extra_data_size = mpeg4_hevc_decoder_configuration_record_save(&ctx->hevc, s_extra_data, sizeof(s_extra_data)); if (extra_data_size <= 0) { // invalid HVCC assert(0); return -1; } // TODO: waiting for key frame ??? ctx->track = mp4_writer_add_video(ctx->mov, MOV_OBJECT_HEVC, ctx->width, ctx->height, s_extra_data, extra_data_size); if (ctx->track < 0) return -1; mp4_writer_init_segment(ctx->mov); } mp4_writer_write(ctx->mov, ctx->track, s_buffer, n, ctx->pts, ctx->pts, 1 == vcl ? MOV_AV_FLAG_KEYFREAME : 0); ctx->pts += 40; ctx->dts += 40; return 0; } static void h265_handler(void* param, const uint8_t* nalu, size_t bytes) { static int i = 0; static int j = 0; static uint8_t startcode[] = {0x00, 0x00, 0x00, 0x01}; struct mov_h265_test_t* ctx = (struct mov_h265_test_t*)param; assert(ctx->ptr < nalu); const uint8_t* ptr = nalu - 3; // const uint8_t* end = (const uint8_t*)nalu + bytes; uint8_t nalutype = (nalu[0] >> 1) & 0x3f; if (ctx->vcl > 0 && h265_is_new_access_unit((const uint8_t*)nalu, bytes)) { //int r = h265_write(ctx, ctx->ptr, ptr - ctx->ptr); int r = h265_write(ctx, ctx->buf, ctx->bytes); if (-1 == r) return; // wait for more data if ((j++) % 25 == 0) i = (i + 1) % ctx->vcl; ctx->bytes = 0; printf("\n"); ctx->ptr = ptr; ctx->vcl = 0; } if (nalutype <= 31) { ++ctx->vcl; if (1 == ctx->vcl || ctx->vcl == i) { printf("ctx->vcl: %d ", ctx->vcl); memcpy(ctx->buf + ctx->bytes, startcode, sizeof(startcode)); ctx->bytes += sizeof(startcode); memcpy(ctx->buf + ctx->bytes, nalu, bytes); ctx->bytes += bytes; } } else { memcpy(ctx->buf + ctx->bytes, startcode, sizeof(startcode)); ctx->bytes += sizeof(startcode); memcpy(ctx->buf + ctx->bytes, nalu, bytes); ctx->bytes += bytes; } } void mov_writer_h265(const char* h265, int width, int height, const char* mp4) { struct mov_h265_test_t ctx; memset(&ctx, 0, sizeof(ctx)); ctx.track = -1; ctx.width = width; ctx.height = height; ctx.bytes = 0; long bytes = 0; uint8_t* ptr = file_read(h265, &bytes); if (NULL == ptr) return; ctx.ptr = ptr; FILE* fp = fopen(mp4, "wb+"); ctx.mov = mp4_writer_create(MOV_WRITER_H265_FMP4, mov_file_buffer(), fp, MOV_FLAG_FASTSTART | MOV_FLAG_SEGMENT); mpeg4_h264_annexb_nalu(ptr, bytes, h265_handler, &ctx); mp4_writer_destroy(ctx.mov); fclose(fp); free(ptr); }