全部產品
Search
文件中心

:HLS基礎介面

更新時間:Oct 19, 2018

OSS MEDIA C SDK 用戶端部分支援將接收到的H.264、AAC格式封裝為TS、M3U8格式,然後寫到OSS上,使用者通過對應的m3u8地址就可以欣賞視頻音頻了。

介面

HLS相關基礎介面都位於oss_media_hls.h中,目前提供的介面有:

  • oss_media_hls_open
  • oss_media_hls_write_frame
  • oss_media_hls_begin_m3u8
  • oss_media_hls_write_m3u8
  • oss_media_hls_end_m3u8
  • oss_media_hls_flush
  • oss_media_hls_close

下面詳細介紹各個介面的功能和注意事項

基礎結構體介紹

  1. /**
  2. * OSS MEDIA HLS FRAME的元資料
  3. */
  4. typedef struct oss_media_hls_frame_s {
  5. stream_type_t stream_type;
  6. frame_type_t frame_type;
  7. uint64_t pts;
  8. uint64_t dts;
  9. uint32_t continuity_counter;
  10. uint8_t key:1;
  11. uint8_t *pos;
  12. uint8_t *end;
  13. } oss_media_hls_frame_t;
  14. /**
  15. * OSS MEDIA HLS的描述資訊
  16. */
  17. typedef struct oss_media_hls_options_s {
  18. uint16_t video_pid;
  19. uint16_t audio_pid;
  20. uint32_t hls_delay_ms;
  21. uint8_t encrypt:1;
  22. char key[OSS_MEDIA_HLS_ENCRYPT_KEY_SIZE];
  23. file_handler_fn_t handler_func;
  24. uint16_t pat_interval_frame_count;
  25. } oss_media_hls_options_t;
  26. /**
  27. * OSS MEDIA HLS FILE的描述資訊
  28. */
  29. typedef struct oss_media_hls_file_s {
  30. oss_media_file_t *file;
  31. oss_media_hls_buf_t *buffer;
  32. oss_media_hls_options_t options;
  33. int64_t frame_count;
  34. } oss_media_hls_file_t;

註:

  • stream_type,流類型, 目前支援st_h264和st_aac兩種
  • frame_type,框架類型,目前支援ft_non_idr,ft_idr,ft_sei,ft_sps,ft_pps,ft_aud等
  • pts,顯示時間戳記
  • dts,解碼時間戳記
  • continuity_counter,遞增計數器,從0-15,起始值不一定取0,但必須是連續的
  • key,是否是主要畫面格
  • pos,當前幀資料的起始位置(含)
  • end,當前幀資料的結束位置(不含)
  • video_pid,視頻的pid
  • audio_pid,音訊pid
  • hls_delay_ms,顯示延遲毫秒數
  • encrypt,是否使用AES-128加密,目前暫不支援
  • key,使用加密時的秘鑰,目前暫不支援
  • handler_func,檔案操作回呼函數
  • pat_interval_frame_count,隔多少幀插入一個pat,mpt表

開啟HLS檔案

  1. /**
  2. * @brief 開啟一個OSS HLS檔案
  3. * @param[in] bucket_name oss上隱藏檔的儲存空間名稱
  4. * @param[in] object_key oss上的檔案名稱
  5. * @param[in] auth_func 授權函數,設定access_key_id/access_key_secret等
  6. * @return:
  7. * 返回非NULL時成功,否則失敗
  8. */
  9. oss_media_hls_file_t* oss_media_hls_open(char *bucket_name, char *object_key, auth_fn_t auth_func);

註:

  • 範例程式碼參考:GitHub

關閉HLS檔案

  1. /**
  2. * @brief 關閉OSS HLS檔案
  3. */
  4. int oss_media_hls_close(oss_media_hls_file_t *file);

註:

  • 範例程式碼參考:GitHub

寫HLS檔案

  1. /**
  2. * @brief 寫H.264或者AAC的一幀資料到oss上
  3. * @param[in] frame h.264或者aac格式的一幀資料
  4. * @param[out] file hls file
  5. * @return:
  6. * 返回0時表示成功
  7. * 否則, 表示出現了錯誤
  8. */
  9. int oss_media_hls_write_frame(oss_media_hls_frame_t *frame, oss_media_hls_file_t *file);

樣本程式:

  1. static void write_frame(oss_media_hls_file_t *file) {
  2. oss_media_hls_frame_t frame;
  3. FILE *file_h264;
  4. uint8_t *buf_h264;
  5. int len_h264, i;
  6. int cur_pos = -1;
  7. int last_pos = -1;
  8. int video_frame_rate = 30;
  9. int max_size = 10 * 1024 * 1024;
  10. char *h264_file_name = "/path/to/example.h264";
  11. /* 讀取H.264檔案 */
  12. buf_h264 = calloc(max_size, 1);
  13. file_h264 = fopen(h264_file_name, "r");
  14. len_h264 = fread(buf_h264, 1, max_size, file_h264);
  15. /* 初始化frame結構體 */
  16. frame.stream_type = st_h264;
  17. frame.pts = 0;
  18. frame.continuity_counter = 1;
  19. frame.key = 1;
  20. /* 遍曆H.264的資料,抽取出每幀資料,然後寫入oss */
  21. for (i = 0; i < len_h264; i++) {
  22. /* 判斷當前位置是否下一幀資料的開頭,也就是當前幀的結尾 */
  23. if ((buf_h264[i] & 0x0F)==0x00 && buf_h264[i+1]==0x00
  24. && buf_h264[i+2]==0x00 && buf_h264[i+3]==0x01)
  25. {
  26. cur_pos = i;
  27. }
  28. /* 如果獲取到完整的一幀資料,就調用介面轉為HLS格式後寫入OSS */
  29. if (last_pos != -1 && cur_pos > last_pos) {
  30. frame.pts += 90000 / video_frame_rate;
  31. frame.dts = frame.pts;
  32. frame.pos = buf_h264 + last_pos;
  33. frame.end = buf_h264 + cur_pos;
  34. oss_media_hls_write_frame(&frame, file);
  35. }
  36. last_pos = cur_pos;
  37. }
  38. /* 關閉檔案,釋放資源 */
  39. fclose(file_h264);
  40. free(buf_h264);
  41. }

註:

  • 範例程式碼參考:GitHub
  • 如果H.264的資料中缺少Access Unit Delimiter NALs(00 00 00 01 09 xx),需要添加這個NAL,否則無法在ipad,iphone,safari上播放
  • H.264的幀是通過0xX0,0x00,0x00,0x01分隔的;AAC的幀是通過0xFF,0x0X分隔的;
  • 當前幀為主要畫面格時,frame.key需要設定為1

寫M3U8檔案

  1. /**
  2. * @brief 寫M3U8檔案的頭部資料
  3. * @param[in] max_duration TS檔案最長期間
  4. * @param[in] sequence TS檔案起始編號
  5. * @param[out] file m3u8 file
  6. * @return:
  7. * 返回0時表示成功
  8. * 否則, 返回-1時表示出現了錯誤
  9. */
  10. void oss_media_hls_begin_m3u8(int32_t max_duration,
  11. int32_t sequence,
  12. oss_media_hls_file_t *file);
  13. /**
  14. * @brief 寫M3U8檔案資料
  15. * @param[in] size m3u8 item個數
  16. * @param[in] m3u8 m3u8 item的詳細資料
  17. * @param[out] file m3u8 file
  18. * @return:
  19. * 返回0時表示成功
  20. * 否則, 返回-1時表示出現了錯誤
  21. */
  22. int oss_media_hls_write_m3u8(int size,
  23. oss_media_hls_m3u8_info_t m3u8[],
  24. oss_media_hls_file_t *file);
  25. /**
  26. * @brief 寫M3U8檔案的結束符等資料
  27. * @param[out] file m3u8 file
  28. */
  29. void oss_media_hls_end_m3u8(oss_media_hls_file_t *file);

樣本程式:

  1. static void write_m3u8() {
  2. char *bucket_name;
  3. char *key;
  4. oss_media_hls_file_t *file;
  5. bucket_name = "<your bucket name>";
  6. key = "<your m3u8 file name>";
  7. /* 開啟一個HLS檔案用來寫M3U8格式的資料,檔案名必須以.m3u8結尾 */
  8. file = oss_media_hls_open(bucket_name, key, auth_func);
  9. if (file == NULL) {
  10. printf("open m3u8 file[%s] failed.", key);
  11. return;
  12. }
  13. /* 構造3個ts格式檔案的資訊 */
  14. oss_media_hls_m3u8_info_t m3u8[3];
  15. m3u8[0].duration = 9;
  16. memcpy(m3u8[0].url, "video-0.ts", strlen("video-0.ts"));
  17. m3u8[1].duration = 10;
  18. memcpy(m3u8[1].url, "video-1.ts", strlen("video-1.ts"));
  19. /* 寫入M3U8檔案
  20. oss_media_hls_begin_m3u8(10, 0, file);
  21. oss_media_hls_write_m3u8(2, m3u8, file);
  22. oss_media_hls_end_m3u8(file);
  23. /* 關閉HLS檔案 */
  24. oss_media_hls_close(file);
  25. printf("write m3u8 to oss file succeeded\n");
  26. }

註:

  • 目前使用的M3U8版本是3
  • 如果是錄播,需要在結束的時候調用oss_media_hls_end_m3u8(file)介面寫入結束符,否則可能無法播放;如果是直播,則不能調用此介面
  • 範例程式碼參考:GitHub
  • 可以通過樣本程式觀看效果
  • Windows平台可以通過VLC播放器觀看,iPhone,iPad,Mac等可以直接使用Safari觀看。