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.

167 lines
3.4KB

  1. #include "h264-file-reader.h"
  2. #include <assert.h>
  3. #include <string.h>
  4. #include <algorithm>
  5. #define H264_NAL(v) (v & 0x1F)
  6. enum { NAL_IDR = 5, NAL_SEI = 6, NAL_SPS = 7, NAL_PPS = 8 };
  7. H264FileReader::H264FileReader(const char* file)
  8. :m_ptr(NULL), m_capacity(0)
  9. {
  10. FILE* fp = fopen(file, "rb");
  11. if(fp)
  12. {
  13. fseek(fp, 0, SEEK_END);
  14. m_capacity = ftell(fp);
  15. fseek(fp, 0, SEEK_SET);
  16. m_ptr = (uint8_t*)malloc(m_capacity);
  17. fread(m_ptr, 1, m_capacity, fp);
  18. fclose(fp);
  19. Init();
  20. }
  21. m_vit = m_videos.begin();
  22. }
  23. H264FileReader::~H264FileReader()
  24. {
  25. if (m_ptr)
  26. {
  27. assert(m_capacity > 0);
  28. free(m_ptr);
  29. }
  30. }
  31. bool H264FileReader::IsOpened() const
  32. {
  33. return !m_videos.empty();
  34. }
  35. int H264FileReader::GetNextFrame(int64_t &dts, const uint8_t* &ptr, size_t &bytes)
  36. {
  37. if(m_vit == m_videos.end())
  38. return -1; // file end
  39. ptr = m_vit->nalu;
  40. dts = m_vit->time;
  41. bytes = m_vit->bytes;
  42. ++m_vit;
  43. return 0;
  44. }
  45. int H264FileReader::Seek(int64_t &dts)
  46. {
  47. vframe_t frame;
  48. frame.time = dts;
  49. vframes_t::iterator it;
  50. it = std::lower_bound(m_videos.begin(), m_videos.end(), frame);
  51. if(it == m_videos.end())
  52. return -1;
  53. while(it != m_videos.begin())
  54. {
  55. if(it->idr)
  56. {
  57. m_vit = it;
  58. return 0;
  59. }
  60. --it;
  61. }
  62. return 0;
  63. }
  64. static inline const uint8_t* search_start_code(const uint8_t* ptr, const uint8_t* end)
  65. {
  66. for(const uint8_t *p = ptr; p + 3 < end; p++)
  67. {
  68. if(0x00 == p[0] && 0x00 == p[1] && (0x01 == p[2] || (0x00==p[2] && 0x01==p[3])))
  69. return p;
  70. }
  71. return end;
  72. }
  73. static inline int h264_nal_type(const unsigned char* ptr)
  74. {
  75. int i = 2;
  76. assert(0x00 == ptr[0] && 0x00 == ptr[1]);
  77. if(0x00 == ptr[2])
  78. ++i;
  79. assert(0x01 == ptr[i]);
  80. return H264_NAL(ptr[i+1]);
  81. }
  82. static inline int h264_nal_new_access(const unsigned char* ptr, const uint8_t* end)
  83. {
  84. int i = 2;
  85. if (end - ptr < 4)
  86. return 1;
  87. assert(0x00 == ptr[0] && 0x00 == ptr[1]);
  88. if (0x00 == ptr[2])
  89. ++i;
  90. assert(0x01 == ptr[i]);
  91. int nal_unit_type = H264_NAL(ptr[i + 1]);
  92. if (nal_unit_type < 1 || nal_unit_type > 5)
  93. return 1;
  94. if (ptr + i + 2 > end)
  95. return 1;
  96. // Live555 H264or5VideoStreamParser::parse
  97. // The high-order bit of the byte after the "nal_unit_header" tells us whether it's
  98. // the start of a new 'access unit' (and thus the current NAL unit ends an 'access unit'):
  99. return (ptr[i + 2] & 0x80) != 0 ? 1 : 0;
  100. }
  101. int H264FileReader::Init()
  102. {
  103. size_t count = 0;
  104. bool spspps = true;
  105. const uint8_t* end = m_ptr + m_capacity;
  106. const uint8_t* nalu = search_start_code(m_ptr, end);
  107. const uint8_t* p = nalu;
  108. while (p < end)
  109. {
  110. const unsigned char* pn = search_start_code(p + 4, end);
  111. size_t bytes = pn - nalu;
  112. int nal_unit_type = h264_nal_type(p);
  113. assert(0 != nal_unit_type);
  114. if(nal_unit_type <= 5 && h264_nal_new_access(pn, end))
  115. {
  116. if(m_sps.size() > 0) spspps = false; // don't need more sps/pps
  117. vframe_t frame;
  118. frame.nalu = nalu;
  119. frame.bytes = (long)bytes;
  120. frame.time = 40 * count++;
  121. frame.idr = 5 == nal_unit_type; // IDR-frame
  122. m_videos.push_back(frame);
  123. nalu = pn;
  124. }
  125. else if(NAL_SPS == nal_unit_type || NAL_PPS == nal_unit_type)
  126. {
  127. if(spspps)
  128. {
  129. size_t n = 0x01 == p[2] ? 3 : 4;
  130. std::pair<const uint8_t*, size_t> pr;
  131. pr.first = p + n;
  132. pr.second = bytes;
  133. m_sps.push_back(pr);
  134. }
  135. }
  136. p = pn;
  137. }
  138. m_duration = 40 * count;
  139. return 0;
  140. }