2016-02-20 6 views
0

Я пытаюсь демонтировать видеофайл в видео часть (h264, mpeg4, h265, vp8, etc) и аудио часть (mp3, aac, ac3, etc) и часть субтитров (srt) с использованием ffmpeg в C++.Извлечение h264 части видеофайла (demuxing)

Звуковая часть вышла в полную силу и сыграна на всех медиаплеерах, которые у меня есть, так же как и часть субтитров. Видео-часть, однако, вышла БЕЗ ошибки и сохранена в файле .h264, но когда я использую ffprobe, чтобы проверить ее или ffplay, чтобы воспроизвести ее, она всегда дает ошибку "Invalid data found when processing input".

Код ниже

/* Separate a media file into audio, video and subtitle files (demuxing, complex) */ 
//TODO: mute error when subtitle is not present 
#define __STDC_CONSTANT_MACROS 

extern "C" 
{ 
    #include "libavformat/avformat.h" 
} 


int main() 
{ 
    //Input AVFormatContext and Output AVFormatContext 
    AVOutputFormat *ofmt_a = NULL, *ofmt_v = NULL, *ofmt_s = NULL; 
    AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx_a = NULL, *ofmt_ctx_v = NULL, *ofmt_ctx_s = NULL; 
    AVPacket pkt; 

    int ret, i; 
    int videoindex=-1, audioindex=-1, srtindex=-1; 
    int frame_index=0; 

    //Input file URL 
    const char *in_filename = "sample.mp4"; 

    //Output file URL 
    const char *out_filename_v = "sample.h264"; 
    const char *out_filename_a = "sample.mp3"; 
    const char *out_filename_s = "sample.srt"; 

    av_register_all(); 

    //Input 
    if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) { 
     printf("Could not open input file."); 
     goto end; 
    } 
    if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) { 
     printf("Failed to retrieve input stream information"); 
     goto end; 
    } 

    //Output 
    avformat_alloc_output_context2(&ofmt_ctx_v, NULL, NULL, out_filename_v); 
    if (!ofmt_ctx_v) { 
     printf("Could not create output context\n"); 
     ret = AVERROR_UNKNOWN; 
     goto end; 
    } 
    ofmt_v = ofmt_ctx_v->oformat; 

    avformat_alloc_output_context2(&ofmt_ctx_a, NULL, NULL, out_filename_a); 
    if (!ofmt_ctx_a) { 
     printf("Could not create output context\n"); 
     ret = AVERROR_UNKNOWN; 
     goto end; 
    } 
    ofmt_a = ofmt_ctx_a->oformat; 

    avformat_alloc_output_context2(&ofmt_ctx_s, NULL, NULL, out_filename_s); 
    if (!ofmt_ctx_a) { 
     printf("Could not create output context\n"); 
     ret = AVERROR_UNKNOWN; 
     goto end; 
    } 
    ofmt_s = ofmt_ctx_s->oformat; 

    for (i = 0; i < ifmt_ctx->nb_streams; i++) { 
      //Create output AVStream according to input AVStream 
      AVFormatContext *ofmt_ctx; 
      AVStream *in_stream = ifmt_ctx->streams[i]; 
      AVStream *out_stream = NULL; 

      if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){ 
       videoindex=i; 
       out_stream=avformat_new_stream(ofmt_ctx_v, in_stream->codec->codec); 
       ofmt_ctx=ofmt_ctx_v; 
      } 
      else if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){ 
       audioindex=i; 
       out_stream=avformat_new_stream(ofmt_ctx_a, in_stream->codec->codec); 
       ofmt_ctx=ofmt_ctx_a; 
      } 
      else if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_SUBTITLE){ 
       srtindex=i; 
       out_stream=avformat_new_stream(ofmt_ctx_s, in_stream->codec->codec); 
       ofmt_ctx=ofmt_ctx_s; 
      } 
      else{ 
       break; 
      } 

      if (!out_stream) { 
       printf("Failed allocating output stream\n"); 
       ret = AVERROR_UNKNOWN; 
       goto end; 
      } 
      //Copy the settings of AVCodecContext 
      if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) { 
       printf("Failed to copy context from input to output stream codec context\n"); 
       goto end; 
      } 
      out_stream->codec->codec_tag = 0; 

      if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) 
       out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; 
    } 

    //Dump Format------------------ 
    printf("\n==============Input Video=============\n"); 
    av_dump_format(ifmt_ctx, 0, in_filename, 0); 

    printf("\n==============Output Video============\n"); 
    av_dump_format(ofmt_ctx_v, 0, out_filename_v, 1); 
    printf("\n==============Output Audio============\n"); 
    av_dump_format(ofmt_ctx_a, 0, out_filename_a, 1); 
    /*printf("\n==============Output Subtitle============\n"); 
    av_dump_format(ofmt_ctx_s, 0, out_filename_s, 1);*/ 
    printf("\n======================================\n"); 

    //Open output file 
    if (!(ofmt_v->flags & AVFMT_NOFILE)) { 
     if (avio_open(&ofmt_ctx_v->pb, out_filename_v, AVIO_FLAG_WRITE) < 0) { 
      printf("Could not open output file '%s'", out_filename_v); 
      goto end; 
     } 
    } 
    if (!(ofmt_a->flags & AVFMT_NOFILE)) { 
     if (avio_open(&ofmt_ctx_a->pb, out_filename_a, AVIO_FLAG_WRITE) < 0) { 
      printf("Could not open output file '%s'", out_filename_a); 
      goto end; 
     } 
    } 
    if (!(ofmt_a->flags & AVFMT_NOFILE)) { 
     if (avio_open(&ofmt_ctx_s->pb, out_filename_s, AVIO_FLAG_WRITE) < 0) { 
      printf("Could not open output file '%s'", out_filename_s); 
      goto end; 
     } 
    } 

    //Write file header 
    if (avformat_write_header(ofmt_ctx_v, NULL) < 0) { 
     printf("Error occurred when opening video output file\n"); 
     goto end; 
    } 
    system("pause"); 


    if (avformat_write_header(ofmt_ctx_a, NULL) < 0) { 
     printf("Error occurred when opening audio output file\n"); 
     goto end; 
    } 
    if (avformat_write_header(ofmt_ctx_s, NULL) < 0) { 
     printf("Error occurred when opening audio output file\n"); 
     goto end; 
    } 

    AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb"); 

    while (1) { 
     AVFormatContext *ofmt_ctx; 
     AVStream *in_stream, *out_stream; 
     //Get an AVPacket 
     if (av_read_frame(ifmt_ctx, &pkt) < 0) 
      break; 
     in_stream = ifmt_ctx->streams[pkt.stream_index]; 


     if(pkt.stream_index==videoindex){ 
      out_stream = ofmt_ctx_v->streams[0]; 
      ofmt_ctx=ofmt_ctx_v; 
      printf("Write Video Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts); 
      av_bitstream_filter_filter(h264bsfc, in_stream->codec, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0); 
     }else if(pkt.stream_index==audioindex){ 
      out_stream = ofmt_ctx_a->streams[0]; 
      ofmt_ctx=ofmt_ctx_a; 
      printf("Write Audio Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts); 
     } 
     else if(pkt.stream_index==srtindex){ 
      out_stream = ofmt_ctx_s->streams[0]; 
      ofmt_ctx=ofmt_ctx_s; 
      printf("Write Subtitle Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts); 
     } 
     else{ 
      continue; 
     } 


     //Convert PTS/DTS 
     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, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); 
     pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base); 
     pkt.pos = -1; 
     pkt.stream_index=0; 
     //Write 
     if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) { 
      printf("Error muxing packet\n"); 
      break; 
     } 
     //printf("Write %8d frames to output file\n",frame_index); 
     av_free_packet(&pkt); 
     frame_index++; 
    } 

    av_bitstream_filter_close(h264bsfc); 

    //Write file trailer 
    av_write_trailer(ofmt_ctx_a); 
    av_write_trailer(ofmt_ctx_v); 
    av_write_trailer(ofmt_ctx_s); 
end: 
    avformat_close_input(&ifmt_ctx); 
    /* close output */ 
    if (ofmt_ctx_a && !(ofmt_a->flags & AVFMT_NOFILE)) 
     avio_close(ofmt_ctx_a->pb); 

    if (ofmt_ctx_v && !(ofmt_v->flags & AVFMT_NOFILE)) 
     avio_close(ofmt_ctx_v->pb); 

    if (ofmt_ctx_s && !(ofmt_s->flags & AVFMT_NOFILE)) 
     avio_close(ofmt_ctx_s->pb); 

    avformat_free_context(ofmt_ctx_a); 
    avformat_free_context(ofmt_ctx_v); 
    avformat_free_context(ofmt_ctx_s); 

    system("pause"); 
    if (ret < 0 && ret != AVERROR_EOF) { 
     printf("Error occurred.\n"); 
     return -1; 
    } 

    return 0; 
} 

EDIT 1 Снимок экрана результирующая h264 файл enter image description here

EDIT 2 Я думаю, что "ошибка" имеет дело с FFmpeg, «Использование AVStream.codec.time_base поскольку временная подсказка для мульсира устарела. Установите AVStream.time_base вместо "error. Я возвращаюсь к старой версии FFMPEG и с тем же кодом, результирующий h264-файл был в порядке!

+0

Зачем вам нужен вызов 'av_bitstream_filter_filter'? Не знаете, что это делает, но не ffmpeg уже передают поток бит H.264 с кодами начала? Я знаю, что это делает для RTSP. В любом случае вы можете вставить какое-то начальное содержимое сгенерированного файла .h264'? –

+0

@ RudolfsBundulis В соответствии с этим вопросом (и отмеченным ответом), я считаю, мне нужен h264_mp4toannexb, чтобы получить надлежащее видео h264. Вопрос обновлен с помощью первых 3 строк файла h264. http://stackoverflow.com/questions/19300350/extracting-h264-raw-video-stream-from-mp4-or-flv-with-ffmpeg-generate-an-invalid?rq=1 – MOHW

+0

это изображение не очень полезно :) Можете ли вы установить плагин Notepad ++ hex editor или открыть файл с любым шестнадцатеричным редактором, чтобы двоичное содержимое было понятным? –

ответ

1

Вам необходимо преобразовать поток бит H.264 из префиксного режима длины, чтобы начать префиксный режим кода. Это требуется для некоторых форматов потоковой передачи, как правило, формата транспортного потока MPEG-2 («mpegts»).

Взгляните на https://www.ffmpeg.org/ffmpeg-bitstream-filters.html#h264_005fmp4toannexb

Посмотрите на линии от 402 до 424 и от 842 до 843. https://www.ffmpeg.org/doxygen/0.7/crystalhd_8c-source.html

Я использовал его, чтобы извлечь из h264 mp4.