天天看点

使用FFMPEG对TS封装H264编码的文件进行NAL的加密

使用ffmpeg-3.3.3和openssl-1.0.2l对TS封装H264编码的文件进行NAL的加密,以下是我实现的接口代码:

//#include "StdAfx.h"
#include "TroubleShoot.h" 
#ifdef __cplusplus //
extern "C"{
#endif

#include "TSEncrypt.h"

#include 
   
    

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavutil/opt.h"

#include 
    
     
#include 
     
      
#include 
      
       
#include 
       
         static FILE *fp_stream=NULL; //输出文件句柄 static unsigned char s_cp_key[SUMA_KEY_AND_IV_LEN]={0}; //cpck static unsigned char s_cp_iv[SUMA_KEY_AND_IV_LEN]={0}; //cpiv static int s_en_type=0; //读文件数据后是否要进行解密处理 static bool enable_encrypt_card=false; //是否启用硬件加密卡 #if 1 //加密 static int aescbc128_encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key, unsigned char *iv, unsigned char *ciphertext) { if((plaintext==NULL)||(plaintext_len==0)||(key==NULL)||(iv==NULL)||(ciphertext==NULL)) return -1; if(enable_encrypt_card) { bool status=false;// = AESEncryptInCBC(plaintext_len,(const BYTE *)plaintext,(const BYTE *)key,(const BYTE *)iv,(BYTE *)ciphertext); if(status) return plaintext_len; else return -1; } else { EVP_CIPHER_CTX *ctx=NULL; int len=0; int ciphertext_len=0; ctx = EVP_CIPHER_CTX_new(); if(ctx==NULL) return -1; EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); EVP_CIPHER_CTX_set_padding(ctx, 0); EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len); ciphertext_len = len; EVP_EncryptFinal_ex(ctx, ciphertext + len, &len); ciphertext_len += len; EVP_CIPHER_CTX_free(ctx); return ciphertext_len; } } //解密 static int aescbc128_decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key, unsigned char *iv, unsigned char *plaintext) { if((ciphertext==NULL)||(ciphertext_len==0)||(key==NULL)||(iv==NULL)||(plaintext==NULL)) return -1; if(enable_encrypt_card) { bool status=false;// = AESDecryptInCBC(ciphertext_len,(const BYTE *)ciphertext,(const BYTE *)key,(const BYTE *)iv,(BYTE *)plaintext); if(status) return ciphertext_len; else return -1; } else { EVP_CIPHER_CTX *ctx=NULL; int len=0; int plaintext_len=0; ctx = EVP_CIPHER_CTX_new(); if(ctx==NULL) return -1; EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv); EVP_CIPHER_CTX_set_padding(ctx, 0); EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len); plaintext_len = len; EVP_DecryptFinal_ex(ctx, plaintext + len, &len); plaintext_len += len; EVP_CIPHER_CTX_free(ctx); return plaintext_len; } } #endif /*全文件加解密接口*/ int Suma_full_file_encrypt_or_decrypt(char *in_path,char *out_path,unsigned char *key,unsigned char *iv,int flag) { struct stat sta_buff; int ret=0; unsigned char *tmp_buf=NULL; unsigned int tmp_buf_size=SUMA_READ_DATA_LEN; unsigned int read_len=0; unsigned int write_len=0; unsigned int total_write_len=0; unsigned int processed_len=0; unsigned int tmp_len=0; FILE* fp_r=NULL; FILE* fp_w=NULL; unsigned char tmp_iv[SUMA_KEY_AND_IV_LEN]={0}; DvtLog(DVT_MSG_TYPE_INFORMATION,"全文件加解密操作开始"); if((in_path==NULL)||(out_path==NULL)||(key==NULL)||(iv==NULL)) { DvtLog(DVT_MSG_TYPE_ERROR,"全文件加解密的参数错误!"); ret=-1; return ret; } ret = stat(in_path, &sta_buff); if(ret != 0) { DvtLog(DVT_MSG_TYPE_ERROR,"全文件加解密时输入文件不存在!"); return ret; } fp_r=fopen(in_path,"rb"); if(fp_r == NULL) { DvtLog(DVT_MSG_TYPE_ERROR,"全文件加解密时打开输入文件失败!"); ret=-1; goto end; } fp_w=fopen(out_path,"wb+"); if(fp_w == NULL) { DvtLog(DVT_MSG_TYPE_ERROR,"全文件加解密时打开输出文件失败!"); ret=-1; goto end; } tmp_buf = (unsigned char *)malloc(tmp_buf_size); if(tmp_buf == NULL) { DvtLog(DVT_MSG_TYPE_ERROR,"全文件加解密时分配缓存失败!"); ret=-1; goto end; } while(sta_buff.st_size>total_write_len) { read_len=fread(tmp_buf,1,tmp_buf_size,fp_r); tmp_len=read_len/SUMA_KEY_AND_IV_LEN*SUMA_KEY_AND_IV_LEN; if(flag == 0) { processed_len = aescbc128_encrypt (tmp_buf, tmp_len, key, iv,tmp_buf); memcpy(iv,tmp_buf+tmp_len-SUMA_KEY_AND_IV_LEN,SUMA_KEY_AND_IV_LEN); } else { memcpy(tmp_iv,tmp_buf+tmp_len-SUMA_KEY_AND_IV_LEN,SUMA_KEY_AND_IV_LEN); processed_len = aescbc128_decrypt (tmp_buf, tmp_len, key, iv,tmp_buf); memcpy(iv,tmp_iv,SUMA_KEY_AND_IV_LEN); } if(processed_len != tmp_len) { DvtLog(DVT_MSG_TYPE_ERROR,"全文件加解密时加解密后的长度不等于原始长度!"); ret=-1; goto end; } write_len = fwrite(tmp_buf,1,read_len,fp_w); if(write_len != read_len) { DvtLog(DVT_MSG_TYPE_ERROR,"全文件加解密时向输出文件写入数据失败!"); ret=-1; goto end; } total_write_len+=write_len; } end: if(tmp_buf != NULL) { free(tmp_buf); tmp_buf=NULL; } if(fp_r != NULL) fclose(fp_r); if(fp_w != NULL) fclose(fp_w); if(ret == 0) DvtLog(DVT_MSG_TYPE_INFORMATION,"全文件加解密操作成功!"); return ret; } /*解密nal单元数据接口*/ static int decrypt_nal_data(unsigned char *key,unsigned char *iv,unsigned char *input,unsigned int in_len,unsigned int *out_len){ unsigned char *bufEncData=NULL; int changed_len=0,k=0,j=0,tmp_buf_data_len=0,decrypt_len=0; unsigned char *tmp_buf=NULL; int ret=-1; if((key==NULL)||(iv==NULL)||(input==NULL)||(out_len==NULL)||(in_len
        
         k+2; j--) bufEncData[j] = bufEncData[j-1]; bufEncData[k+2] = 0x03; dwLen++; continue; } if(bufEncData[k] == 0x0 && bufEncData[k+1] == 0x0 && bufEncData[k+2] == 0x03 /*&& bufEncData[k+3] > 0x03*/){ for(j=dwLen; j>k+2; j--) bufEncData[j] = bufEncData[j-1]; bufEncData[k+2] = 0x03; dwLen++; continue; } } return 0; } static int read_file(void *opaque, uint8_t *buf, int buf_size){ if((buf==NULL)||(buf_size==0)){ return -1; } if(!feof(fp_stream)){ int read_len=fread(buf,1,buf_size,fp_stream); if(s_en_type == 0){ unsigned char tmp_iv[SUMA_KEY_AND_IV_LEN]={0}; unsigned int tmp_len=0; /*因为是读取部分数据,所以需要记录下一次解密需要使用的iv*/ tmp_len=read_len/SUMA_KEY_AND_IV_LEN*SUMA_KEY_AND_IV_LEN; memcpy(tmp_iv,buf+(tmp_len-SUMA_KEY_AND_IV_LEN),SUMA_KEY_AND_IV_LEN); /*解密*/ int processed_len = aescbc128_decrypt (buf, tmp_len, s_cp_key, s_cp_iv,buf); /*下一次解密的iv赋值*/ memcpy(s_cp_iv,tmp_iv,SUMA_KEY_AND_IV_LEN); } return read_len; }else{ return -1; } } static int open_file(int type,char *input,char *output,AVFormatContext** ic,AVFormatContext** oc,int *video_index) { int ret=0; struct stat sta_buff; unsigned char *aviobuffer = NULL; AVIOContext *avio = NULL; AVOutputFormat* ofmt = NULL; AVStream* video_st = NULL; AVStream* audio_st = NULL; unsigned int i = 0; char szError[256] = {0}; /*判断文件是否存在*/ ret = stat(input, &sta_buff); if(ret != 0){ DvtLog(DVT_MSG_TYPE_ERROR,"未找到输入文件!"); return ret; } av_register_all(); if(type==0) { /*以流的方式打开需要加密的文件*/ fp_stream=fopen(input,"rb"); if(fp_stream == NULL){ DvtLog(DVT_MSG_TYPE_ERROR,"打开输入文件失败!"); ret=-1; goto end; } *ic = avformat_alloc_context(); if(ic == NULL){ DvtLog(DVT_MSG_TYPE_ERROR,"分配输入文件ic失败!"); goto end; } aviobuffer=(unsigned char *)av_malloc(SUMA_READ_DATA_LEN); if(aviobuffer == NULL){ DvtLog(DVT_MSG_TYPE_ERROR,"分配缓存aviobuffer失败!"); ret=-1; goto end; } avio =avio_alloc_context(aviobuffer, SUMA_READ_DATA_LEN,0,NULL,read_file,NULL,NULL); if(avio == NULL){ DvtLog(DVT_MSG_TYPE_ERROR,"分配avio失败!"); ret=-1; goto end; } (*ic)->pb=avio; ret = avformat_open_input(ic,NULL,NULL,NULL); } else { ret = avformat_open_input(ic, input, NULL, NULL); } if(ret != 0){ av_strerror(ret, szError, 256); DvtLog(DVT_MSG_TYPE_ERROR,"ic avformat_open_input失败:%s!",szError); goto end; } /*flags中有AVFMT_FLAG_KEEP_SIDE_DATA应该不会添加额外的14字节的数据 0x8c4d9d108e25e9feULL*/ (*ic)->flags|=AVFMT_FLAG_KEEP_SIDE_DATA; if ((ret = avformat_find_stream_info(*ic, 0)) < 0) { DvtLog(DVT_MSG_TYPE_ERROR,"Failed to retrieve input stream information!"); goto end; } av_dump_format(*ic, 0, input, 0); //输出(Output) avformat_alloc_output_context2(oc, NULL, NULL, output); if (!*oc) { DvtLog(DVT_MSG_TYPE_ERROR,"Could not create output context!"); ret = AVERROR_UNKNOWN; goto end; } (*oc)->flags|=AVFMT_FLAG_KEEP_SIDE_DATA; ofmt = (*oc)->oformat; for (i = 0; i < (*ic)->nb_streams; i++) { //根据输入流创建输出流(Create output AVStream according to input AVStream) AVStream *in_stream = (*ic)->streams[i]; AVStream *out_stream = avformat_new_stream((*oc), in_stream->codec->codec); if (!out_stream) { DvtLog(DVT_MSG_TYPE_ERROR,"Failed allocating output stream!"); ret = AVERROR_UNKNOWN; goto end; } //复制AVCodecContext的设置(Copy the settings of AVCodecContext) ret = avcodec_copy_context(out_stream->codec, in_stream->codec); if (ret < 0) { DvtLog(DVT_MSG_TYPE_ERROR,"Failed to copy context from input to output stream codec context!"); goto end; } /*拷贝codecpar ffmpeg后续会使用codecpar替换codec参数 需要给out_stream的codecpar赋值*/ //memcpy(out_stream->codecpar,in_stream->codecpar,sizeof(AVCodecParameters)); ret = avcodec_parameters_copy(out_stream->codecpar,in_stream->codecpar); if (ret < 0) { DvtLog(DVT_MSG_TYPE_ERROR,"failed to avcodec_parameters_copy"); goto end; } out_stream->codec->codec_tag = 0; if ((*oc)->oformat->flags & AVFMT_GLOBALHEADER) out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; if(in_stream->codec->codec_type==AVMEDIA_TYPE_VIDEO) *video_index = i; /*异常情况 音频流的采样率为0 强制设置这可能有问题*/ if((out_stream->codec->codec_type==AVMEDIA_TYPE_AUDIO)&&(out_stream->codecpar->sample_rate==0)) { out_stream->codecpar->sample_rate=48000; DvtLog(DVT_MSG_TYPE_WARNING,"audio out_stream->codecpar->sample_rate==0"); } AVCodecContext* input_codec_context = NULL; AVCodecContext* output_codec_context = NULL; input_codec_context = in_stream->codec; output_codec_context = out_stream->codec; if (av_q2d(input_codec_context->time_base) * input_codec_context->ticks_per_frame > av_q2d(in_stream->time_base) && av_q2d(in_stream->time_base) < 1.0 / 1000) { output_codec_context->time_base = input_codec_context->time_base; output_codec_context->time_base.num *= input_codec_context->ticks_per_frame; } else { output_codec_context->time_base = in_stream->time_base; } } //输出一下格式------------------ av_dump_format(*oc, 0, output, 1); //打开输出文件(Open output file) if (!(ofmt->flags & AVFMT_NOFILE)) { ret = avio_open(&((*oc)->pb), output, AVIO_FLAG_WRITE); if (ret < 0) { DvtLog(DVT_MSG_TYPE_ERROR,"Could not open output file '%s'",output); goto end; } } //写文件头(Write file header) ret = avformat_write_header(*oc, NULL); if (ret < 0) { DvtLog(DVT_MSG_TYPE_ERROR,"Error occurred when opening output file!"); goto end; } /*flags中有AVFMT_FLAG_KEEP_SIDE_DATA应该不会添加额外的14字节的数据 0x8c4d9d108e25e9feULL*/ //(*ic)->flags|=AVFMT_FLAG_KEEP_SIDE_DATA; //(*oc)->flags|=AVFMT_FLAG_KEEP_SIDE_DATA; end: return ret; } static bool ParseH264Nal(unsigned char* pbyData,unsigned int data_len,unsigned int *nal_len,unsigned int* pbyUnitType,unsigned int *offset,unsigned int *en_len) { unsigned int wOffset = 0,i=0; //判断是否是NAL单元 if ((0 == pbyData[0]) && (0 == pbyData[1])){ if (1 == pbyData[2]){ wOffset += 3; } else if ((0 == pbyData[2]) && (1 == pbyData[3])){ wOffset += 4; } else return false; } else return false; *pbyUnitType = 0x1f & pbyData[wOffset]; if(*pbyUnitType==5||*pbyUnitType==1){ //数据单元,海思平台输入的数据中只有一个有效的数据单元 *nal_len = data_len; if(*nal_len>wOffset+32) { wOffset += 32; *en_len = *nal_len - wOffset; *offset=wOffset; } else { *offset=0; *en_len=0; } } else{ //描述单元,逐字节分析找到下一个单元的头来确认当前单元长度 for(i=0;i
         
          en_type; enable_encrypt_card = info->enable_encrypt_card; /*如果需要先全文件解密 给cpck cpiv赋值 在读文件时就解密*/ if(s_en_type==0){ memcpy(s_cp_key,info->de_key,SUMA_KEY_AND_IV_LEN); memcpy(s_cp_iv,info->de_iv,SUMA_KEY_AND_IV_LEN); } int video_index = -1; ret = open_file(0,info->in_path,info->out_path,&ic,&oc,&video_index); if(ret!=0) { DvtLog(DVT_MSG_TYPE_INFORMATION,"open_file failed!"); return ret; } packet=(AVPacket *)av_malloc(sizeof(AVPacket)); packet_dst=(AVPacket *)av_malloc(sizeof(AVPacket)); if((packet==NULL)||(packet_dst==NULL)) { DvtLog(DVT_MSG_TYPE_INFORMATION,"packet为NULL!"); ret=-1; goto end; } unsigned int frame_index=0; int64_t last_pts=0,last_dts=0,base_duration=0; /*拆包得到一帧数据,音频数据不做处理,仅处理视频数据*/ do{ decode_done = av_read_frame(ic, packet); if (decode_done < 0){ break; } /*视频数据*/ if(packet->stream_index==video_index){ unsigned int tmp_packet_size=0; tmp_packet_size=packet->size; for(i=0;i
          
           data+i; /*解析视频数据应包含多个NAL,其中多个描述NAL和一个数据NAL*/ nal_status = ParseH264Nal(pbyINData,tmp_packet_size-i,&nal_len,&pbyUnitType,&offset,&en_len); if(nal_status){ /*数据NAL,且能够加密*/ if((pbyUnitType==1||pbyUnitType==5)&&(en_len>=16)){ /*先解密*/ if(s_en_type==1){ decrypt_nal_data(info->de_key,info->de_iv,pbyINData+offset,en_len,&changed_len); if(en_len>changed_len) { packet->size=packet->size-(en_len-changed_len); tmp_packet_size=tmp_packet_size-(en_len-changed_len); en_len=changed_len; } }//s_en_type==1 encrypt_nal_data(info->en_key,info->en_iv,pbyINData+offset,en_len,&changed_len); if(changed_len>en_len){ /*创建新的packet*/ av_new_packet(packet_dst, packet->size+changed_len-en_len); /*拷贝packet*/ av_packet_copy_props(packet_dst, packet); memcpy(packet_dst->data,packet->data,packet_dst->size); ambiguity_add(packet_dst->data+i+offset,en_len); ambiguity_flag=1; } }//nal data i+=nal_len; }//nal else break; }//for packet #if 0 AVStream *in_stream, *out_stream; in_stream = ic->streams[packet->stream_index]; out_stream = oc->streams[packet->stream_index]; /* copy packet */ packet->pts = av_rescale_q_rnd(packet->pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); packet->dts = av_rescale_q_rnd(packet->dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); packet->duration = av_rescale_q(packet->duration, in_stream->time_base, out_stream->time_base); #endif }//video /*如果没二义性处理直接写packet 如果有的话写packet_dst*/ if(ambiguity_flag==0) ret = av_interleaved_write_frame(oc, packet); else{ ret = av_interleaved_write_frame(oc, packet_dst); av_free_packet(packet_dst); ambiguity_flag=0; } if (ret < 0){ av_strerror(ret, szError, 256); DvtLog(DVT_MSG_TYPE_WARNING,"oc av_interleaved_write_frame失败:%s!",szError); } else if (ret > 0) { DvtLog(DVT_MSG_TYPE_INFORMATION,"End of stream requested!"); av_free_packet(packet); break; } av_free_packet(packet); }while(!decode_done); av_write_trailer(oc); avio_close(oc->pb); avformat_free_context(oc); //avformat_close_input(&ic); end: if(packet!=NULL){ av_free(packet); } if(packet_dst!=NULL){ av_free(packet_dst); } if(ic!=NULL){ //avformat_free_context(ic); avformat_close_input(&ic); } if(fp_stream!=NULL){ fclose(fp_stream); } if(ret==0) DvtLog(DVT_MSG_TYPE_INFORMATION,"Suma_TSEncrypt OK!"); return ret; } int Suma_decrypt_file(char *in_path,char *out_path,unsigned char *key,unsigned char *iv,bool enable_hw) { AVFormatContext* ic = NULL; AVFormatContext* oc = NULL; unsigned int i = 0; int nRet =0; char szError[256] = {0}; static AVPacket *packet=NULL; int encrypt_flag=0; int video_index=-1; if((in_path==NULL)||(in_path==NULL)||(key==NULL)||(iv==NULL)) { DvtLog(DVT_MSG_TYPE_INFORMATION,"输入参数指针为NULL!"); return -1; } /*是否启动加密卡标识*/ enable_encrypt_card=enable_hw; nRet = open_file(1,in_path,out_path,&ic,&oc,&video_index); if(nRet!=0) { DvtLog(DVT_MSG_TYPE_INFORMATION,"open_file failed!"); return -1; } packet=(AVPacket *)av_malloc(sizeof(AVPacket)); if(packet==NULL) { DvtLog(DVT_MSG_TYPE_INFORMATION,"packet为NULL!"); return -1; } int decode_done = 0; do { decode_done = av_read_frame(ic, packet); if (decode_done < 0) { Sleep(25); break; } /*只对视频处理*/ if(packet->stream_index==video_index){ long unsigned int dwOutLen=0; unsigned char* pbyINData=NULL; unsigned char* pbyOutData=NULL; unsigned int nal_len=0,k=0; bool nal_status=false; int nResult=-1; unsigned int pbyUnitType=0,offset=0,en_len=0,changed_len=0; for(i=0;i
           
            size;) { pbyINData = (unsigned char*)packet->data+i; /*解析视频数据应包含多个NAL,其中多个描述NAL和一个数据NAL*/ nal_status = ParseH264Nal(pbyINData,packet->size-i,&nal_len,&pbyUnitType,&offset,&en_len); if(nal_status) { /*数据NAL,且能够加密*/ if((pbyUnitType==1||pbyUnitType==5)&&(en_len>=16)) { decrypt_nal_data(key,iv,pbyINData+offset,en_len,&changed_len); packet->size=packet->size-(en_len-changed_len); encrypt_flag=1; }// 1 5 encrypt i+=nal_len; }//nal else break; }//nal for }//video frame else{ } nRet = av_interleaved_write_frame(oc, packet); if (nRet < 0) { av_strerror(nRet, szError, 256); DvtLog(DVT_MSG_TYPE_WARNING,"oc av_interleaved_write_frame失败:%s!",szError); } else if (nRet > 0) { DvtLog(DVT_MSG_TYPE_INFORMATION,"End of stream requested!"); av_free_packet(packet); break; } av_free_packet(packet); }while(!decode_done); av_write_trailer(oc); avio_close(oc->pb); avformat_free_context(oc); avformat_close_input(&ic); if(packet!=NULL) { av_free(packet); } DvtLog(DVT_MSG_TYPE_INFORMATION,"Suma_decrypt_file OK!"); return 0; } static char cmd[SUMA_CMD_LEN]={0}; int Suma_TStoHLS(TStoHLSInfo *info){ struct stat sta_buff; int ret=0; char *tmp=NULL; char input_filename[SUMA_PATH_LEN]={0}; char drive[3]={0}; if(info==NULL) return -1; ret = stat(info->in_path, &sta_buff); if(ret != 0) { DvtLog(DVT_MSG_TYPE_ERROR,"Suma_TStoHLS输入文件不存在!"); return ret; } int size = strlen(info->in_path); for(int i=0; i
            
             in_path[i] == '\\') info->in_path[i] = '/'; } /*获取输入文件名*/ tmp = strrchr(info->in_path,'/'); if(tmp==NULL) { DvtLog(DVT_MSG_TYPE_ERROR,"Suma_TStoHLS输入文件不是绝对路径!"); return -1; } memcpy(input_filename,tmp+1,strlen(tmp)-1); tmp = strrchr(input_filename,'.'); if(tmp!=NULL) { memset(input_filename+(strlen(input_filename)-strlen(tmp)),0,strlen(tmp)); } ret = stat(info->tools_path, &sta_buff); if(ret != 0) { DvtLog(DVT_MSG_TYPE_ERROR,"Suma_TStoHLS切片工具不存在!"); return ret; } /*如果输出目录不存在则创建输出目录*/ ret = stat(info->out_path, &sta_buff); if(ret != 0) { memset(cmd,0,SUMA_CMD_LEN); sprintf(cmd,"mkdir \"%s\"",info->out_path); ret = system(cmd); if(ret != 0) { DvtLog(DVT_MSG_TYPE_ERROR,"Suma_TStoHLS创建目录失败!"); return ret; } } /*获取输出目录的盘符*/ memcpy(drive,info->out_path,2); /*先进入输出目录所在盘 再进入输出目录 创建对应输入文件名的目录 进入新创建的目录 开始切片*/ memset(cmd,0,SUMA_CMD_LEN); sprintf(cmd,"%s & cd %s & %s -i %s -y -vcodec copy -acodec copy -map 0 -f segment -segment_list %s.m3u8 -segment_time %d %s-%s.ts", drive,info->out_path,info->tools_path,info->in_path,input_filename,info->duration,input_filename,"%05d"); ret = system(cmd); if(ret != 0) { DvtLog(DVT_MSG_TYPE_ERROR,"Suma_TStoHLS切片失败!"); return ret; } /*m3u8文件处理*/ FILE *fp_m3u8=NULL; char m3u8_filename[SUMA_PATH_LEN]={0}; char ext_x_key[SUMA_CMD_LEN]={0}; char strLine[1024]={0}; unsigned int seek_len=0; sprintf(m3u8_filename,"%s/%s.m3u8",info->out_path,input_filename); ret = stat(m3u8_filename, &sta_buff); if(ret != 0) { DvtLog(DVT_MSG_TYPE_ERROR,"Suma_TStoHLS m3u8文件不存在!"); return ret; } fp_m3u8 = fopen(m3u8_filename,"rb"); if(fp_m3u8==NULL) { DvtLog(DVT_MSG_TYPE_ERROR,"Suma_TStoHLS打开m3u8文件失败!"); return ret; } while (!feof(fp_m3u8)) //循环读取每一行,直到文件尾 { fgets(strLine,1024,fp_m3u8); //将fp所指向的文件一行内容读到strLine缓冲区 seek_len+=strlen(strLine); ret =memcmp(strLine,"#EXT-X-TARGETDURATION",strlen("#EXT-X-TARGETDURATION")); if(ret==0) break; //DO SOMETHING ELSE } fseek(fp_m3u8,0,SEEK_SET); char *tmp_buf = (char *)malloc(sta_buff.st_size); fread(tmp_buf,1,sta_buff.st_size,fp_m3u8); fclose(fp_m3u8); fp_m3u8 = fopen(m3u8_filename,"wb+"); fwrite(tmp_buf,1,seek_len,fp_m3u8); sprintf(ext_x_key,"#EXT-X-KEY:METHOD=SAMPLE-AES,VDECFORMAT=\"h264\",KEYFORMATVERSIONS=\"1\",KEYFORMAT=\"shctdrm\",IV=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x,URI=\"%s?KeyID=%s\"\n", info->iv[0],info->iv[1],info->iv[2],info->iv[3], info->iv[4],info->iv[5],info->iv[6],info->iv[7], info->iv[8],info->iv[9],info->iv[10],info->iv[11], info->iv[12],info->iv[13],info->iv[14],info->iv[15], info->drmserver_url,info->keyid); fwrite(ext_x_key,1,strlen(ext_x_key),fp_m3u8); fwrite(tmp_buf+seek_len,1,sta_buff.st_size-seek_len,fp_m3u8); fclose(fp_m3u8); if(tmp_buf!=NULL) free(tmp_buf); DvtLog(DVT_MSG_TYPE_INFORMATION,"Suma_TStoHLS OK!"); return ret; } #endif } #ifdef __cplusplus } #endif
            
           
          
         
        
       
      
     
    
   
           

因为需要对源文件进行保护,所以源文件是进行了全文件的sample-aes加密处理的,在做NAL加密之前需要先对整个文件进行解密,所以在读文件时使用流的方式,读到数据先解密,读到packet之后再进行NAL加密,加密之后要进行防二义性的处理,进行这个处理之后数据可能会变大,需重新分配一个packet来保存数据。

对NAL加密之后的TS文件,有需求使用新的密钥重新加密,接口中也添加对这个需求的处理。