微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用来自 libav (FFMPEG)

如何解决使用来自 libav (FFMPEG)

所以我的最终目标是拥有一个加密的 RTSP 流。 首先,我尝试对本地视频文件进行编码,然后使用 FFPLAY.exe 对其进行测试。我已经使用 FFMPEG(参考:FFmpeg: how to produce MP4 CENC (Common Encryption) videos)找到了用于此的测试命令,但是找不到使用 libav 实现此目的的单个示例:/

根据 libav 文档,AES 类下只有三种方法:av_aes_alloc、av_aes_init 和 av_aes_crypt。首先我想知道如何解决这个问题?如果有一种方法可以从 libav 中定义 key_id?

我目前加密 AVPacket-> 数据的方法似乎不起作用!

if ((ret = avformat_open_input(&ifmt_ctx,in_filename,0)) < 0) {
    fprintf(stderr,"Could not open input file '%s'",in_filename);
    return ResetParams();
}

if ((ret = avformat_find_stream_info(ifmt_ctx,"Failed to retrieve input stream information");
    return ResetParams();
}

av_dump_format(ifmt_ctx,0);

avformat_alloc_output_context2(&ofmt_ctx,NULL,out_filename);
if (!ofmt_ctx) {
    fprintf(stderr,"Could not create output context\n");
    ret = AVERROR_UNKNowN;
    return ResetParams();
}

stream_mapping_size = ifmt_ctx->nb_streams;
stream_mapping = new int(stream_mapping_size);

if (!stream_mapping) {
    ret = AVERROR(ENOMEM);
    return ResetParams();
}

ofmt = ofmt_ctx->oformat;

for (i = 0; i < ifmt_ctx->nb_streams; i++) {
    AVStream* out_stream;
    AVStream* in_stream = ifmt_ctx->streams[i];
    AVCodecParameters* in_codecpar = in_stream->codecpar;

    if (in_codecpar->codec_type != AVMEDIA_TYPE_AUdio &&
        in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
        in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
        stream_mapping[i] = -1;
        continue;
    }

    stream_mapping[i] = stream_index++;

    out_stream = avformat_new_stream(ofmt_ctx,NULL);
    if (!out_stream) {
        fprintf(stderr,"Failed allocating output stream\n");
        ret = AVERROR_UNKNowN;
        return ResetParams();
    }

    ret = avcodec_parameters_copy(out_stream->codecpar,in_codecpar);
    if (ret < 0) {
        fprintf(stderr,"Failed to copy codec parameters\n");
        return ResetParams();
    }
    out_stream->codecpar->codec_tag = 0;
}

av_dump_format(ofmt_ctx,out_filename,1);


if (!(ofmt->flags & AVFMT_NOFILE)) {
    ret = avio_open(&ofmt_ctx->pb,AVIO_FLAG_WRITE);
    if (ret < 0) {
        fprintf(stderr,"Could not open output file '%s'",out_filename);
        return ResetParams();
    }
}

ret = avformat_write_header(ofmt_ctx,NULL);
if (ret < 0) {
    fprintf(stderr,"Error occurred when opening output file\n");
    return ResetParams();
}

while (1) {
    AVStream* in_stream,* out_stream;

    ret = av_read_frame(ifmt_ctx,&pkt);
    if (ret < 0)
        break;

    in_stream = ifmt_ctx->streams[pkt.stream_index];
    if (pkt.stream_index >= stream_mapping_size ||
        stream_mapping[pkt.stream_index] < 0) {
        av_packet_unref(&pkt);
        continue;
    }

    pkt.stream_index = stream_mapping[pkt.stream_index];
    out_stream = ofmt_ctx->streams[pkt.stream_index];
    //log_packet(ifmt_ctx,&pkt,"in");

    /* copy packet */
    pkt.pts = av_rescale_q_rnd(pkt.pts,in_stream->time_base,out_stream->time_base,(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    pkt.dts = av_rescale_q_rnd(pkt.dts,(AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    pkt.duration = av_rescale_q(pkt.duration,out_stream->time_base);
    pkt.pos = -1;
    //log_packet(ofmt_ctx,"out");

    EncryptAVPacket(&pkt);

    ret = av_interleaved_write_frame(ofmt_ctx,&pkt);
    if (ret < 0) {
        fprintf(stderr,"Error muxing packet\n");
        break;
    }
    av_packet_unref(&pkt);
}

av_write_trailer(ofmt_ctx);

加密AVPacket方法如下:

void EncryptAVPacket(AVPacket* pkt)
{
    int size = pkt->size;
    int count = 0;  //no of 16 byte blocks
    if (size % 16 == 0)
        count = size / 16;
    else
    {
        av_grow_packet(pkt,size % 16);
        size = pkt->size;
        count = size / 16;
    }

    av_aes_crypt(avaes,pkt->data,count,(uint8_t*)iv,0);
}

虽然写入加密视频成功,但是ffplay无法播放文件。下面是 ffplay 控制台的快照。

enter image description here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。