2017-10-16 8 views
1

私はffmpegを初めて使う人です。私はFFmpegFrameGrabberとJavaCPP(バージョン1.3.3)を使用してmp4ビデオファイルのパケットを取得しています。データが要求された時点でパケットをデコードし、イメージを処理するために、パケットのバイトストリームをデータベースに保存したいと思います。私のコードでJavaのFFmpegのデコードavcodec_decode_video2のAVPacketの結果

public static void saveVideoToDB(String pathToVideo){ 
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(pathToVideo); 
grabber.start(); 
AVPacket pkt; 
while ((pkt = grabber.grabPacket()) != null) { 
    BytePointer data = pkt.data(); 
    data.capacity(pkt.size()); 
    byte[] arr = data.getStringBytes(); 
    //arr = [0, 0, 0, 62, 39, 100, 0, 40, -83, -124.....] 
    if (pkt.stream_index() == AVMEDIA_TYPE_VIDEO) { 
     //ToDo: save arr to database 
     testDecode(arr); 
    } 


} 
grabber.close(); 
logger.info("Import video finished."); 
} 

私は最初の概念実証のために、パケットのデータをデコードしようとしたが、それはこのように働いている場合、私はわからない:

public static void testDecode(byte[] data){ 
    AVCodec avCodec = avcodec_find_decoder(AV_CODEC_ID_H264); 
    AVCodecContext avCodecContext = avcodec_alloc_context3(avCodec); 
    AVDictionary opts = new AVDictionary(); 
    avcodec_open2(avCodecContext, avCodec, opts); 
    av_dict_free(opts); 
    AVFrame avFrame = av_frame_alloc(); 
    AVPacket avPacket = new AVPacket(); 
    av_init_packet(avPacket); 
    Frame frame = new Frame(); 
    avPacket.pts(AV_NOPTS_VALUE); 
    avPacket.dts(AV_NOPTS_VALUE); 
    BytePointer bp = new BytePointer(data); 
    bp.capacity(data.length); 
    avPacket.data(bp); 
    avPacket.size(data.length); 
    avPacket.pos(-1); 

    IntBuffer gotPicture = IntBuffer.allocate(1); 
    boolean doVideo = true; 
    boolean keyFrames = false; 
    boolean processImage = true; 
    AVPacket pkt = avPacket; 
    if (doVideo) { 
     int len = avcodec_decode_video2(avCodecContext, avFrame, gotPicture, avPacket); 
     if (len >= 0 && gotPicture.get(0) != 0 
      && (!keyFrames || avFrame.pict_type() == AV_PICTURE_TYPE_I)) { 
     //ToDo: process image 
     logger.info("decode success"); 
     }else{ 
     logger.info("decode failed"); 
     } 
    } 
    } 

avcodec_decode_video2の結果であります常に負(入力を処理するときに-1094995529 =>無効なデータが見つかりました)とIは、次のエラーを受け取る:

[H264 @ 00000000214d11a0】なしスタートコードが検出されません。

[h264 @ 00000000214d11a0]入力をNAL単位に分割する際にエラーが発生しました。ここで

入力からいくつかのメタデータです。

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\Users\user01\Documents\fullstream.mp4': 
    Metadata: 
    major_brand  : mp42 
    minor_version : 0 
    compatible_brands: mp42mp41isomiso2 
    creation_time : 2017-07-27T11:17:19.000000Z 
    Duration: 00:55:55.48, start: 0.000000, bitrate: 5126 kb/s 
    Stream #0:0(eng): Video: h264 (High) (avc1/0x31637661), yuv420p, 1920x1080, 4996 kb/s, 25 fps, 25 tbr, 2500 tbn, 5k tbc (default) 
    Metadata: 
     creation_time : 2017-07-27T11:17:19.000000Z 
     handler_name : VideoHandler 
    Stream #0:1(eng): Audio: mp3 (mp4a/0x6134706D), 24000 Hz, mono, s16p, 125 kb/s (default) 
    Metadata: 
     creation_time : 2017-07-27T11:17:19.000000Z 
     handler_name : SoundHandler 
+0

あなたはAVPacket.stream_index'が有効 'AVMEDIA_TYPE_VIDEO'ストリームである'チェックしていません。 – WLGfx

+0

あなたの提案をありがとう。私は質問を更新しましたが、同じエラーです。 –

答えて

1

は申し訳ありませんが、私はあなたのJavaのものCにffmpegの++はなく、知っています。 あなたの問題は、mpeg4デコーダに実際にフィードしているものが明確でないことです。生のmpeg4ストリームをフィードすることしかできません。

私のお勧めは、libavcodecとjavaの典型的なCタイプの使い方の違いを教えてください。 Cで

私達はちょうどデコーダにビデオバイナリデータを供給するようにしてくださいするためにこのような何かを:

while(av_read_frame(pFormatCtx, &packet)>=0) { 
    // Is this a packet from the video stream? 
    if(packet.stream_index==videoStream) { 
    // Decode video frame 
    avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet); 
    ... 

あなたのコードを見てみると、私はFFmpegFrameGrabberマップはav_read_frameする方法を知らないと、ご利用くださいほとんどの文字列関数は、いくつかのバイトの変換を行う傾向があり、ビデオのもので、私たちが扱っているので、あなたの関数呼び出しに非常に近い外観は

byte[] arr = data.getStringBytes(); 

に用語「文字列」がここに含まれていることを裸の事実は、私にとっては恐ろしいですバイナリデータ。

P.S. ...私はこの1つで何とか興味を持って、私はどんな質問や、あなたのソリューションをお聞かせくださいavcodec_decode_video2のビデオフレームを取得するために、単一のチャンクだけではなく、より多くのデータを読み込む必要があるかもしれません。あなたのビデオの最初のフレームがIframeであるとは思わない。あなたのプログラムがファイルの最初から最後まで読んでみる前に、私が上に書いたものに集中する前に

編集2:あなたのプログラムをテストするための生のh264ストリームにあなたの入力をフォーマットしてみてください。 ffmpeg -i test.mp4 -vcodec copy -an c:\ temp \ test.h264を使用してください。

+0

お返事ありがとうございます!作業する前に、入力を生のh264ストリームにフォーマットします。問題は、入力がAVC1(開始コードのないH.264ビットストリーム)であり、avcodec_decode_video2が開始コード{0,0,0,1}のH.264ビットストリームを必要としているようです。前に入力を変換することは私のために働いていますが、私はここで何が最善の解決策であるかを考えようとしています。おそらく、実行時にAVPacketをスタートコードでビットストリームに変換する方法があります。 h264_mp4toannexbのようなビットストリームフィルタは有望だと思います... –

1

上記の答えが私のために働いていました。さらに、私は解決策のようなJavaを投稿したい:AVBitStreamFilterはトリックをした追加:

public static void saveVideoToDB(String pathToVideo){ 
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(pathToVideo); 
grabber.start(); 
//added this 
AVStream v_stream = oc.streams(AVMEDIA_TYPE_VIDEO); 
AVCodecContext codec = v_stream.codec();  
AVBitStreamFilterContext h264bsfc = av_bitstream_filter_init("h264_mp4toannexb"); 
AVPacket pkt; 
while ((pkt = grabber.grabPacket()) != null) { 
    //and this 
    av_apply_bitstream_filters(codec, pkt, h264bsfc); 
    BytePointer data = pkt.data(); 
    data.capacity(pkt.size()); 
    byte[] arr = data.getStringBytes(); 
    if (pkt.stream_index() == AVMEDIA_TYPE_VIDEO) { 
     testDecode(arr); 
    } 


} 
av_bitstream_filter_close(h264bsfc); 
grabber.close(); 
logger.info("Import video finished."); 
} 
+0

最終的なコードを投稿するための忠告は、それを共有してくれてありがとう! – Harry

関連する問題