閱讀94 返回首頁    go iPhone_iPad_Mac_apple


HLS基礎接口__Media-C-SDK_SDK 參考_對象存儲 OSS-阿裏雲

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

下麵詳細介紹各個接口的功能和注意事項

基礎結構體介紹

/**
 *  OSS MEDIA HLS FRAME的元數據
 */
typedef struct oss_media_hls_frame_s {
    stream_type_t stream_type;
    frame_type_t frame_type;
    uint64_t pts;
    uint64_t dts;
    uint32_t continuity_counter;
    uint8_t  key:1;
    uint8_t *pos;
    uint8_t *end;
} oss_media_hls_frame_t;

/**
 *  OSS MEDIA HLS的描述信息
 */
typedef struct oss_media_hls_options_s {
    uint16_t video_pid;
    uint16_t audio_pid;
    uint32_t hls_delay_ms;
    uint8_t encrypt:1;
    char    key[OSS_MEDIA_HLS_ENCRYPT_KEY_SIZE];
    file_handler_fn_t handler_func;
    uint16_t pat_interval_frame_count;
} oss_media_hls_options_t;

/**
 *  OSS MEDIA HLS FILE的描述信息
 */
typedef struct oss_media_hls_file_s {
    oss_media_file_t *file;
    oss_media_hls_buf_t *buffer;
    oss_media_hls_options_t options;
    int64_t frame_count;
} 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文件

/**
 *  @brief  打開一個OSS HLS文件
 *  @param[in]  bucket_name oss上存儲文件的存儲空間名稱
 *  @param[in]  object_key  oss上的文件名稱
 *  @param[in]  auth_func   授權函數,設置access_key_id/access_key_secret等
 *  @return:
 *      返回非NULL時成功,否則失敗
 */
oss_media_hls_file_t* oss_media_hls_open(char *bucket_name, char *object_key, auth_fn_t auth_func);

注:

關閉HLS文件

/**
 *  @brief  關閉OSS HLS文件
 */
int oss_media_hls_close(oss_media_hls_file_t *file);

注:

寫HLS文件

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

示例程序:

static void write_frame(oss_media_hls_file_t *file) {
    oss_media_hls_frame_t frame;
    FILE    *file_h264;
    uint8_t *buf_h264;
    int     len_h264, i;
    int     cur_pos = -1;
    int     last_pos = -1;
    int     video_frame_rate = 30;
    int     max_size = 10 * 1024 * 1024;
    char    *h264_file_name = "/path/to/example.h264";

    /* 讀取H.264文件 */
    buf_h264 = calloc(max_size, 1);
    file_h264 = fopen(h264_file_name, "r");
    len_h264 = fread(buf_h264, 1, max_size, file_h264);

    /* 初始化frame結構體 */
    frame.stream_type = st_h264;
    frame.pts = 0;
    frame.continuity_counter = 1;
    frame.key = 1;

    /* 遍曆H.264的數據,抽取出每幀數據,然後寫入oss */
    for (i = 0; i < len_h264; i++) {
        /*  判斷當前位置是否下一幀數據的開頭,也就是當前幀的結尾 */
        if ((buf_h264[i] & 0x0F)==0x00 && buf_h264[i+1]==0x00 
            && buf_h264[i+2]==0x00 && buf_h264[i+3]==0x01) 
        {
            cur_pos = i;
        }

    /* 如果獲取到完整的一幀數據,就調用接口轉為HLS格式後寫入OSS */
        if (last_pos != -1 && cur_pos > last_pos) {
            frame.pts += 90000 / video_frame_rate;
            frame.dts = frame.pts;

            frame.pos = buf_h264 + last_pos;
            frame.end = buf_h264 + cur_pos;

            oss_media_hls_write_frame(&frame, file);
        }

        last_pos = cur_pos;
    }

    /* 關閉文件,釋放資源 */
    fclose(file_h264);
    free(buf_h264);
}

注:

  • 示例代碼參考: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文件

/**
 *  @brief  寫M3U8文件的頭部數據
 *  @param[in]  max_duration  TS文件最長持續時間
 *  @param[in]  sequence      TS文件起始編號
 *  @param[out] file          m3u8 file
 *  @return:
 *      返回0時表示成功
 *      否則, 返回-1時表示出現了錯誤
 */
void oss_media_hls_begin_m3u8(int32_t max_duration, 
                              int32_t sequence,
                              oss_media_hls_file_t *file);

/**
 *  @brief  寫M3U8文件數據
 *  @param[in]  size          m3u8 item個數
 *  @param[in]  m3u8          m3u8 item的詳細數據
 *  @param[out] file          m3u8 file
 *  @return:
 *      返回0時表示成功
 *      否則, 返回-1時表示出現了錯誤
 */
int oss_media_hls_write_m3u8(int size,
                             oss_media_hls_m3u8_info_t m3u8[],
                             oss_media_hls_file_t *file);

/**
 *  @brief  寫M3U8文件的結束符等數據
 *  @param[out] file          m3u8 file
 */
void oss_media_hls_end_m3u8(oss_media_hls_file_t *file);

示例程序:

static void write_m3u8() {
    char *bucket_name;
    char *key;
    oss_media_hls_file_t *file;

    bucket_name = "<your bucket name>";
    key = "<your m3u8 file name>";

    /* 打開一個HLS文件用來寫M3U8格式的數據,文件名必須以.m3u8結尾 */
    file = oss_media_hls_open(bucket_name, key, auth_func);
    if (file == NULL) {
        printf("open m3u8 file[%s] failed.", key);
        return;
    }

    /* 構造3個ts格式文件的信息 */
    oss_media_hls_m3u8_info_t m3u8[3];
    m3u8[0].duration = 9;
    memcpy(m3u8[0].url, "video-0.ts", strlen("video-0.ts"));
    m3u8[1].duration = 10;
    memcpy(m3u8[1].url, "video-1.ts", strlen("video-1.ts"));

    /* 寫入M3U8文件
    oss_media_hls_begin_m3u8(10, 0, file);
    oss_media_hls_write_m3u8(2, m3u8, file);
    oss_media_hls_end_m3u8(file);

    /* 關閉HLS文件 */
    oss_media_hls_close(file);

    printf("write m3u8 to oss file succeededn");
}

注:

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

最後更新:2016-11-23 16:04:11

  上一篇:go 服務端__Media-C-SDK_SDK 參考_對象存儲 OSS-阿裏雲
  下一篇:go HLS封裝接口__Media-C-SDK_SDK 參考_對象存儲 OSS-阿裏雲