首页 > 解决方案 > 对于自定义 FFmpeg I/O API:关于 avio_alloc_context() 的 write_packet 回调函数的数据不正确

问题描述

我想问一个关于ffmpeg custom I/O api的问题。

问题描述:我用FFmpeg官方例子-remuxing.c测试了一个简单的转换包操作。(test1.ts -> test1.mp4)。这个操作结果是正常的。但是当我使用自定义 I/O

avio_alloc_context(buf, 65535, 1, nullptr, nullptr, write_cb, seek);

函数,自定义I/O输出写入内存,然后从这个内存写入mp4文件。发现输出文件数据与 Internal file Protocol write 不同。VLC 和 MediaInfo 无法探测它。

我使用Beyond Compare4来比较文件数据:

Beyond Compare 4 图片比较

这张图左边是我自定义的I/O输出右边是官方的例子(根据文件URLProtocol来输出)

我测试了很多次,每次数据大小、数据位置、数据内容都在同一个地方。当我将左边有差异的几个字节的数据更改为右边的数据时,VLC可以正常播放。

是我的操作不当,还是其他问题?

源代码:

extern "C"{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
}
#include <unistd.h>
#include <cstdio>
#include <fcntl.h>
void process_error(int ret, const char* info)
{
   if( ret < 0)
   {
      fprintf(stderr, info);
      std::exit(-1);
   }
}
int fd;
int write_packet(void *opaque, uint8_t *buf, int buf_size)
 {
      int ret;
      ret = write(fd, buf, buf_size);
      printf("write bytes %d\n", ret);
      return (ret == -1) ? AVERROR(errno) : ret;
 }
 int64_t seek(void *opaque, int64_t offset, int whence)
 {
      return offset;
 }

 int main()
 {

     fd = open("/home/oaho/Desktop/22.mp4", O_CREAT | O_WRONLY, 0777);
     if ( fd < 0)
     {
        return -1;
     }


     AVFormatContext *inputContext = nullptr;
     AVFormatContext *ouputContext = nullptr;

     int ret = avformat_open_input(&inputContext, "/home/oaho/Desktop/test1.ts", nullptr, nullptr);
     process_error(ret, "could'not open input\n");
     ret = avformat_find_stream_info(inputContext, nullptr);
     process_error(ret, "could'not find stream information\n");

     avformat_alloc_output_context2(&ouputContext, nullptr, "mp4", nullptr);
     if( ouputContext == nullptr)
     process_error(-1, "could'not alloc outputContext\n");


     if( ouputContext->oformat==nullptr)
     {
        ouputContext->oformat = av_guess_format("mp4", nullptr, nullptr);
     }

     uint8_t* buf = nullptr;
     buf = (uint8_t*)av_malloc(200 * 1024);
     if( buf == nullptr)
     {
        return -1;
     }
     ouputContext->pb = nullptr;
     ouputContext->pb = avio_alloc_context(buf, 200 * 1024, 1, nullptr, nullptr, write_packet, seek);
     if( ouputContext->pb == nullptr)
     {
        return -1;
     }
     ouputContext->flags = AVFMT_FLAG_CUSTOM_IO;
     //pre the stream avalible
     int *arr = new int[inputContext->nb_streams];
     if( arr == nullptr )
       process_error(-1, "can't alloc array\n");
     int stream_index = 0;
     //get stream : video stream , audio stream , subtitle stream
     for(int i = 0;i < inputContext->nb_streams;i++)
     {
        //get the single stream
        AVStream *stream = inputContext->streams[i];
        AVStream *outStream = nullptr;
        AVCodecParameters *codec = stream->codecpar;
        if(   codec -> codec_type != AVMediaType::AVMEDIA_TYPE_VIDEO
           && codec -> codec_type != AVMediaType::AVMEDIA_TYPE_AUDIO
           && codec -> codec_type != AVMediaType::AVMEDIA_TYPE_SUBTITLE)
        {
            arr[i] = -1;
            continue;
        }
        arr[i] = stream_index++;
        outStream = avformat_new_stream(ouputContext, nullptr);
        if(outStream == nullptr)
           goto end;
        int ret = avcodec_parameters_copy(outStream->codecpar, stream->codecpar);
        if( ret < 0)
           goto end;
         //not include additional information
        outStream->codecpar->codec_tag = 0;
      }
      ret = avformat_write_header(ouputContext, nullptr);
      process_error(ret, "can't write header\n");

      while(1)
      {
          AVPacket pkt;
          av_init_packet(&pkt);
          AVStream *in_stream, *out_stream;
          ret = av_read_frame(inputContext, &pkt);
          if( ret < 0)
             break;  
          in_stream  = inputContext->streams[pkt.stream_index];
          if (arr[pkt.stream_index] < 0) {
             av_packet_unref(&pkt);
             continue;
          }
          pkt.stream_index = arr[pkt.stream_index];
          out_stream = ouputContext->streams[pkt.stream_index];
          /* copy packet */
          pkt.pts = av_rescale_q(pkt.pts, in_stream->time_base, out_stream->time_base);
          pkt.dts = av_rescale_q(pkt.dts, in_stream->time_base, out_stream->time_base);
          pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
          pkt.pos = -1;
          //log_packet(ofmt_ctx, &pkt, "out");
          ret = av_interleaved_write_frame(ouputContext, &pkt);
          if (ret < 0) {
            fprintf(stderr, "Error muxing packet\n");
            break;
          }
          av_packet_unref(&pkt);
       }
       av_write_trailer(ouputContext);
  end:
       close(fd);
       delete [] arr;
       avformat_free_context(inputContext);
       avformat_free_context(ouputContext);
       return 0;
 }

标签: c++ffmpeg

解决方案


推荐阅读