You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

129 lines
3.0KB

  1. #include "mp4-writer.h"
  2. #include "mov-format.h"
  3. #include "mpeg4-avc.h"
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <assert.h>
  8. #define MOV_WRITER_H264_FMP4 0
  9. extern "C" const struct mov_buffer_t* mov_file_buffer(void);
  10. #define H264_NAL(v) (v & 0x1F)
  11. static uint8_t s_buffer[2 * 1024 * 1024];
  12. static uint8_t s_extra_data[64 * 1024];
  13. struct mov_h264_test_t
  14. {
  15. struct mp4_writer_t* mov;
  16. struct mpeg4_avc_t avc;
  17. int track;
  18. int width;
  19. int height;
  20. uint32_t pts, dts;
  21. const uint8_t* ptr;
  22. int vcl;
  23. };
  24. static uint8_t* file_read(const char* file, long* size)
  25. {
  26. FILE* fp = fopen(file, "rb");
  27. if (fp)
  28. {
  29. fseek(fp, 0, SEEK_END);
  30. *size = ftell(fp);
  31. fseek(fp, 0, SEEK_SET);
  32. uint8_t* ptr = (uint8_t*)malloc(*size);
  33. fread(ptr, 1, *size, fp);
  34. fclose(fp);
  35. return ptr;
  36. }
  37. return NULL;
  38. }
  39. static int h264_write(struct mov_h264_test_t* ctx, const void* data, int bytes)
  40. {
  41. int vcl = 0;
  42. int update = 0;
  43. int n = h264_annexbtomp4(&ctx->avc, data, bytes, s_buffer, sizeof(s_buffer), &vcl, &update);
  44. if (ctx->track < 0)
  45. {
  46. if (ctx->avc.nb_sps < 1 || ctx->avc.nb_pps < 1)
  47. {
  48. //ctx->ptr = end;
  49. return -2; // waiting for sps/pps
  50. }
  51. int extra_data_size = mpeg4_avc_decoder_configuration_record_save(&ctx->avc, s_extra_data, sizeof(s_extra_data));
  52. if (extra_data_size <= 0)
  53. {
  54. // invalid AVCC
  55. assert(0);
  56. return -1;
  57. }
  58. // TODO: waiting for key frame ???
  59. ctx->track = mp4_writer_add_video(ctx->mov, MOV_OBJECT_H264, ctx->width, ctx->height, s_extra_data, extra_data_size);
  60. if (ctx->track < 0)
  61. return -1;
  62. mp4_writer_init_segment(ctx->mov);
  63. }
  64. mp4_writer_write(ctx->mov, ctx->track, s_buffer, n, ctx->pts, ctx->pts, 1 == vcl ? MOV_AV_FLAG_KEYFREAME : 0);
  65. ctx->pts += 40;
  66. ctx->dts += 40;
  67. return 0;
  68. }
  69. static void h264_handler(void* param, const uint8_t* nalu, size_t bytes)
  70. {
  71. struct mov_h264_test_t* ctx = (struct mov_h264_test_t*)param;
  72. assert(ctx->ptr < nalu);
  73. const uint8_t* ptr = nalu - 3;
  74. // const uint8_t* end = (const uint8_t*)nalu + bytes;
  75. uint8_t nalutype = nalu[0] & 0x1f;
  76. if (ctx->vcl > 0 && h264_is_new_access_unit((const uint8_t*)nalu, bytes))
  77. {
  78. int r = h264_write(ctx, ctx->ptr, ptr - ctx->ptr);
  79. if (-1 == r)
  80. return; // wait for more data
  81. ctx->ptr = ptr;
  82. ctx->vcl = 0;
  83. }
  84. if (1 <= nalutype && nalutype <= 5)
  85. ++ctx->vcl;
  86. }
  87. void mov_writer_h264(const char* h264, int width, int height, const char* mp4)
  88. {
  89. struct mov_h264_test_t ctx;
  90. memset(&ctx, 0, sizeof(ctx));
  91. ctx.track = -1;
  92. ctx.width = width;
  93. ctx.height = height;
  94. long bytes = 0;
  95. uint8_t* ptr = file_read(h264, &bytes);
  96. if (NULL == ptr) return;
  97. ctx.ptr = ptr;
  98. FILE* fp = fopen(mp4, "wb+");
  99. ctx.mov = mp4_writer_create(MOV_WRITER_H264_FMP4, mov_file_buffer(), fp, MOV_FLAG_FASTSTART | MOV_FLAG_SEGMENT);
  100. mpeg4_h264_annexb_nalu(ptr, bytes, h264_handler, &ctx);
  101. mp4_writer_destroy(ctx.mov);
  102. fclose(fp);
  103. free(ptr);
  104. }