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.

172 lines
6.1KB

  1. #include "webm-vpx.h"
  2. #include "mpeg4-bits.h"
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <assert.h>
  6. enum {
  7. WEBM_VP_LEVEL_1 = 10,
  8. WEBM_VP_LEVEL_1_1 = 11,
  9. WEBM_VP_LEVEL_2 = 20,
  10. WEBM_VP_LEVEL_2_1 = 21,
  11. WEBM_VP_LEVEL_3 = 30,
  12. WEBM_VP_LEVEL_3_1 = 31,
  13. WEBM_VP_LEVEL_4 = 40,
  14. WEBM_VP_LEVEL_4_1 = 41,
  15. WEBM_VP_LEVEL_5 = 50,
  16. WEBM_VP_LEVEL_5_1 = 51,
  17. WEBM_VP_LEVEL_5_2 = 52,
  18. WEBM_VP_LEVEL_6 = 60,
  19. WEBM_VP_LEVEL_6_1 = 61,
  20. WEBM_VP_LEVEL_6_2 = 62,
  21. };
  22. /*
  23. aligned (8) class VPCodecConfigurationRecord {
  24. unsigned int (8) profile;
  25. unsigned int (8) level;
  26. unsigned int (4) bitDepth;
  27. unsigned int (3) chromaSubsampling;
  28. unsigned int (1) videoFullRangeFlag;
  29. unsigned int (8) colourPrimaries;
  30. unsigned int (8) transferCharacteristics;
  31. unsigned int (8) matrixCoefficients;
  32. unsigned int (16) codecIntializationDataSize;
  33. unsigned int (8)[] codecIntializationData;
  34. }
  35. */
  36. int webm_vpx_codec_configuration_record_load(const uint8_t* data, size_t bytes, struct webm_vpx_t* vpx)
  37. {
  38. if (bytes < 8)
  39. return -1;
  40. vpx->profile = data[0];
  41. vpx->level = data[1];
  42. vpx->bit_depth = (data[2] >> 4) & 0x0F;
  43. vpx->chroma_subsampling = (data[2] >> 1) & 0x07;
  44. vpx->video_full_range_flag = data[2] & 0x01;
  45. vpx->colour_primaries = data[3];
  46. vpx->transfer_characteristics = data[4];
  47. vpx->matrix_coefficients = data[5];
  48. vpx->codec_intialization_data_size = (((uint16_t)data[6]) << 8) | data[7];
  49. assert(0 == vpx->codec_intialization_data_size);
  50. return 8;
  51. }
  52. int webm_vpx_codec_configuration_record_save(const struct webm_vpx_t* vpx, uint8_t* data, size_t bytes)
  53. {
  54. if (bytes < 8 + (size_t)vpx->codec_intialization_data_size)
  55. return 0; // don't have enough memory
  56. data[0] = vpx->profile;
  57. data[1] = vpx->level;
  58. data[2] = (vpx->bit_depth << 4) | ((vpx->chroma_subsampling & 0x07) << 1) | (vpx->video_full_range_flag & 0x01);
  59. data[3] = vpx->colour_primaries;
  60. data[4] = vpx->transfer_characteristics;
  61. data[5] = vpx->matrix_coefficients;
  62. data[6] = (uint8_t)(vpx->codec_intialization_data_size >> 8);
  63. data[7] = (uint8_t)vpx->codec_intialization_data_size;
  64. if(vpx->codec_intialization_data_size > 0)
  65. memcpy(data + 8, vpx->codec_intialization_data, vpx->codec_intialization_data_size);
  66. return 8 + vpx->codec_intialization_data_size;
  67. }
  68. // https://www.webmproject.org/vp9/mp4/
  69. // https://github.com/webmproject/vp9-dash
  70. // https://www.rfc-editor.org/rfc/pdfrfc/rfc6386.txt.pdf
  71. // https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf
  72. int webm_vpx_codec_configuration_record_from_vp8(struct webm_vpx_t* vpx, int *width, int* height, const void* keyframe, size_t bytes)
  73. {
  74. uint32_t tag;
  75. const uint8_t* p;
  76. const uint8_t startcode[] = { 0x9d, 0x01, 0x2a };
  77. if (bytes < 10)
  78. return -1;
  79. p = (const uint8_t*)keyframe;
  80. // 9.1. Uncompressed Data Chunk
  81. tag = (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16);
  82. //key_frame = tag & 0x01;
  83. //version = (tag >> 1) & 0x07;
  84. //show_frame = (tag >> 4) & 0x1;
  85. //first_part_size = (tag >> 5) & 0x7FFFF;
  86. if (0 != (tag & 0x01) || startcode[0] != p[3] || startcode[1] != p[4] || startcode[2] != p[5])
  87. return -1; // not key frame
  88. *width = ((uint16_t)(p[7] & 0x3F) << 8) | (uint16_t)(p[6]); // (2 bits Horizontal Scale << 14) | Width (14 bits)
  89. *height = ((uint16_t)(p[9] & 0x3F) << 8) | (uint16_t)(p[8]); // (2 bits Vertical Scale << 14) | Height (14 bits)
  90. memset(vpx, 0, sizeof(*vpx));
  91. vpx->profile = (tag >> 1) & 0x03;
  92. vpx->level = 31;
  93. vpx->bit_depth = 8;
  94. return 0;
  95. }
  96. // https://storage.googleapis.com/downloads.webmproject.org/docs/vp9/vp9-bitstream-specification-v0.6-20160331-draft.pdf
  97. int webm_vpx_codec_configuration_record_from_vp9(struct webm_vpx_t* vpx, int* width, int* height, const void* keyframe, size_t bytes)
  98. {
  99. const uint8_t* p;
  100. struct mpeg4_bits_t bits;
  101. const uint8_t frame_sync_code[] = { 0x49, 0x83, 0x42 };
  102. p = (const uint8_t*)keyframe;
  103. if (bytes < 4 || frame_sync_code[0] != p[1] || frame_sync_code[1] != p[2] || frame_sync_code[2] != p[3])
  104. return -1;
  105. memset(vpx, 0, sizeof(*vpx));
  106. vpx->level = 31;
  107. // 6.2 Uncompressed header syntax
  108. mpeg4_bits_init(&bits, (void*)keyframe, bytes);
  109. mpeg4_bits_read_n(&bits, 2); // 2-frame_marker
  110. vpx->profile = (uint8_t)(mpeg4_bits_read(&bits) | (mpeg4_bits_read(&bits) << 1)); // 2-profile_low_bit+profile_high_bit
  111. mpeg4_bits_read_n(&bits, 4 + 24); // skip 4-bits + frame_sync_code
  112. // color_config()
  113. if (vpx->profile >= 2)
  114. vpx->bit_depth = (uint8_t)mpeg4_bits_read(&bits) ? 12 : 10; // 1-ten_or_twelve_bit
  115. else
  116. vpx->bit_depth = 8;
  117. if (7 /*CS_RGB*/ != mpeg4_bits_read_n(&bits, 3)) // 3-color_space
  118. {
  119. vpx->video_full_range_flag = (uint8_t)mpeg4_bits_read(&bits); // color_range
  120. if (1 == vpx->profile || 3 == vpx->profile)
  121. {
  122. vpx->chroma_subsampling = 3 - (uint8_t)mpeg4_bits_read_n(&bits, 2); // subsampling_x/subsampling_y
  123. mpeg4_bits_read(&bits); // reserved_zero
  124. }
  125. }
  126. else
  127. {
  128. if (1 == vpx->profile || 3 == vpx->profile)
  129. mpeg4_bits_read(&bits); // reserved_zero
  130. }
  131. // frame_size()
  132. *width = (int)mpeg4_bits_read_n(&bits, 16) + 1;
  133. *height = (int)mpeg4_bits_read_n(&bits, 16) + 1;
  134. return mpeg4_bits_error(&bits) ? -1 : 0;
  135. }
  136. #if defined(_DEBUG) || defined(DEBUG)
  137. void webm_vpx_test(void)
  138. {
  139. const unsigned char src[] = {
  140. 0x00, 0x1f, 0x80, 0x02, 0x02, 0x02, 0x00, 0x00
  141. };
  142. unsigned char data[sizeof(src)];
  143. struct webm_vpx_t vpx;
  144. assert(sizeof(src) == webm_vpx_codec_configuration_record_load(src, sizeof(src), &vpx));
  145. assert(0 == vpx.profile && 31 == vpx.level && 8 == vpx.bit_depth && 0 == vpx.chroma_subsampling && 0 == vpx.video_full_range_flag);
  146. assert(sizeof(src) == webm_vpx_codec_configuration_record_save(&vpx, data, sizeof(data)));
  147. assert(0 == memcmp(src, data, sizeof(src)));
  148. }
  149. #endif