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

来源:互联网 发布:麦迪生涯数据统计 编辑:程序博客网 时间:2024/05/01 03:58
使用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};//cpckstatic unsigned char s_cp_iv[SUMA_KEY_AND_IV_LEN]={0};//cpivstatic 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;elsereturn -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;elsereturn -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_lenk+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;}elsereturn false;}elsereturn 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;ien_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;idata+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==1encrypt_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 datai+=nal_len;}//nalelsebreak;}//for packet#if 0AVStream *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;isize;){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 encrypti+=nal_len;}//nalelsebreak;}//nal for}//video frameelse{}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; iin_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文件,有需求使用新的密钥重新加密,接口中也添加对这个需求的处理。
原创粉丝点击