2016-10-23 4 views
1

AVFrame(AVPicture)の出力がANativeWindowに問題があります。私はいくつかの動画の次の問題に直面Android用簡易FFMpegプレーヤー

void *Player::readThread(void * reserved) { 
    ALOGD("Read thread started!"); 
    VideoState *state = (VideoState *) reserved; 

    int err = 0; 
    int ret; 
    int i; 
    AVFormatContext *formatContext = NULL; 
    AVCodecContext *codecContext = NULL; 
    AVCodecParameters *codecParams = NULL; 
    AVCodecID codecID = AV_CODEC_ID_NONE; 
    AVCodec *decoder = NULL; 
    AVFrame *frame = NULL; 
    AVFrame *frameRGBA = NULL; 
    AVPacket packet; 
    struct SwsContext *img2RGBAContext; 
    ANativeWindow_Buffer windowBuffer; 
    uint8_t *RGBABuffer = NULL; 
    int RGBABufferSize = 0; 
    int got = 0; 
    int windowWidth = 640; 
    int windowHeight = 480; 

    const char *url = state->url.c_str(); 
    if (url == NULL || strlen(url) <= 0) { 
     err = ERROR_UNKNOWN_URI; 
     goto exit; 
    } 
    ALOGD("URL to play: %s", url); 

    state->isPlaying = true; 

    formatContext = avformat_alloc_context(); 
    if (formatContext == NULL) { 
     err = ERROR_OUT_OF_MEMORY; 
     goto exit; 
    } 
    ALOGD("formatContext allocated"); 

    frame = av_frame_alloc(); 
    if (frame == NULL) { 
     err = ERROR_OUT_OF_MEMORY; 
     goto exit; 
    } 
    ALOGD("frame allocated"); 

    frameRGBA = av_frame_alloc(); 
    if (frameRGBA == NULL) { 
     err = ERROR_OUT_OF_MEMORY; 
     goto exit; 
    } 
    ALOGD("frameRGBA allocated"); 

    ret = avformat_open_input(&formatContext, url, NULL, NULL); 
    if (ret != 0) { 
     err = ERROR_CAN_NOT_OPEN_URI; 
     goto exit; 
    } 
    ALOGD("formatContext opened"); 

    ret = avformat_find_stream_info(formatContext, NULL); 
    if (ret != 0) { 
     err = ERROR_CAN_NOT_FIND_STREAM_INFO; 
     goto exit; 
    } 
    ALOGD("file info found"); 

    for (i = 0; i < formatContext->nb_streams; i++) { 
     AVStream *stream = formatContext->streams[i]; 
     AVCodecParameters *codecParams = stream->codecpar; 
     AVCodecID codecID = codecParams->codec_id; 
     AVMediaType type = codecParams->codec_type; 
     const char *codecName = avcodec_get_name(codecID); 
     switch (type) { 
      case AVMEDIA_TYPE_AUDIO: 
       ALOGD("Stream [%d]: type=AUDIO codecName=%s",i,codecName); 
       break; 
      case AVMEDIA_TYPE_VIDEO: 
       ALOGD("Stream [%d]: type=VIDEO codecName=%s",i,codecName); 
       if (state->video_stream == -1) { 
        state->video_stream = i; 
       } 
       break; 
      case AVMEDIA_TYPE_SUBTITLE: 
       ALOGD("Stream [%d]: type=SUBTITLE codecName=%s",i,codecName); 
       break; 
      default: 
       ALOGD("Stream [%d]: type=UNKNOWN codecName=%s",i,codecName); 
       break; 
     } 
    } 

    if (state->video_stream == -1) { 
     err = ERROR_CAN_NOT_FIND_ANY_STREAM; 
     goto exit; 
    } 
    ALOGD("Video stream index: %d",state->video_stream); 

    codecParams = formatContext->streams[state->video_stream]->codecpar; 
    codecID = codecParams->codec_id; 
    if (codecID == AV_CODEC_ID_NONE) { 
     err = ERROR_UNKNOWN_CODEC; 
     goto exit; 
    } 
    ALOGD("Codec found"); 

    decoder = avcodec_find_decoder(codecID); 
    if (decoder == NULL) { 
     err = ERROR_CAN_NOT_FIND_DECODER; 
     goto exit; 
    } 
    ALOGD("Decoder found"); 

    codecContext = avcodec_alloc_context3(decoder); 
    if (codecContext == NULL) { 
     err = ERROR_OUT_OF_MEMORY; 
     goto exit; 
    } 
    ALOGD("codecContext created"); 

    ret = avcodec_parameters_to_context(codecContext, codecParams); 
    if (ret < 0) { 
     err = ERROR_CAN_NOT_START_DECODER; 
     goto exit; 
    } 
    ALOGD("codecContext params was set"); 

    ret = avcodec_open2(codecContext, decoder, NULL); 
    if (ret != 0) { 
     err = ERROR_CAN_NOT_START_DECODER; 
     goto exit; 
    } 
    ALOGD("Decoder opened"); 

    if (state->window != NULL) { 
     ANativeWindow_setBuffersGeometry(state->window, codecParams->width, codecParams->height, WINDOW_FORMAT_RGB_565); 
     ALOGD("Window geometry changed"); 
    } 

    if (codecParams->width>0 && codecParams->height>0) { 
     ALOGD("Video width: %d\nVideo height: %d",codecParams->width, codecParams->height); 
     img2RGBAContext = sws_getCachedContext(
      NULL, 
      codecParams->width, 
      codecParams->height, 
      (AVPixelFormat)codecParams->format, 
      codecParams->width, 
      codecParams->height, 
      AV_PIX_FMT_RGB565, 
      SWS_BICUBIC, 
      NULL, 
      NULL, 
      NULL); 
     if (img2RGBAContext == NULL) { 
      err = ERROR_OUT_OF_MEMORY; 
      goto exit; 
     } 
    } else { 
     err = ERROR_CAN_NOT_START_DECODER; 
     goto exit; 
    } 
    ALOGD("img2RGBAContext created"); 

    RGBABufferSize = av_image_get_buffer_size(AV_PIX_FMT_RGB565, codecParams->width, codecParams->height, 1); 
    RGBABuffer = (uint8_t *)malloc(RGBABufferSize*sizeof(uint8_t)); 
    if (RGBABuffer == NULL) { 
     err = ERROR_OUT_OF_MEMORY; 
     goto exit; 
    } 
    ALOGD("frameRGBABuffer size %d bytes",RGBABufferSize); 

    ret = av_image_alloc(frameRGBA->data, frameRGBA->linesize, codecParams->width, codecParams->height, AV_PIX_FMT_RGB565, 1); 
    if (ret < 0) { 
     err = ERROR_OUT_OF_MEMORY; 
     goto exit; 
    } 

    while (av_read_frame(formatContext, &packet) >= 0 && state->isPlaying) { 
     if (packet.stream_index != state->video_stream) { 
      ALOGD("Packet is not a video packet. Discard."); 
      av_packet_unref(&packet); 
      continue; 
     } 
     ret = avcodec_send_packet(codecContext, &packet); 
     if (ret != 0) { 
      ALOGE("Can not send packet to decode"); 
      av_packet_unref(&packet); 
      continue; 
     } 
     ret = avcodec_receive_frame(codecContext, frame); 
     if (ret != 0) { 
      ALOGE("Can not receive decoded frame yet"); 
      av_packet_unref(&packet); 
      continue; 
     } 
     ALOGD("Converting image to RGB565..."); 
     sws_scale(img2RGBAContext, frame->data, frame->linesize, 0, codecParams->height, frameRGBA->data, frameRGBA->linesize); 
     ALOGD("Image converted to RGB565"); 
     av_image_copy_to_buffer(RGBABuffer, 
      RGBABufferSize, 
      frameRGBA->data, 
      frameRGBA->linesize, 
      AV_PIX_FMT_RGB565, 
      codecParams->width, 
      codecParams->height, 
      1); 
     ALOGD("Image wrote into frameRGBABuffer"); 
     if (ANativeWindow_lock(state->window, &windowBuffer, NULL) == 0) { 
      ALOGD("Writing %d bytes to windowBuffer", RGBABufferSize); 
      memcpy(windowBuffer.bits, RGBABuffer, RGBABufferSize); 
      ANativeWindow_unlockAndPost(state->window); 
      ALOGD("Image displayed"); 
     } else { 
      ALOGE("Can not display frame"); 
     } 
     av_packet_unref(&packet); 
    } 

    exit: 
    ALOGD("Releasing resources..."); 
    if (err!=0) { 
     state->isPlaying = false; 
     #if !LOG_NDEBUG 
      switch (err) { 
       case ERROR_OUT_OF_MEMORY: 
        ALOGE("Out of memory!"); 
        break; 
       case ERROR_CAN_NOT_OPEN_URI: 
        ALOGE("Can not open URI: %s", url); 
        break; 
       case ERROR_UNKNOWN_URI: 
        ALOGE("Unknown URI to open!"); 
        break; 
       default: 
        ALOGE("Unknown error"); 
        break; 
      } 
     #endif 
     // TODO: send error to listener 
    } 
    sws_freeContext(img2RGBAContext); 
    free(RGBABuffer); 
    av_free(frame); 
    av_freep(&frameRGBA->data[0]); 
    av_packet_unref(&packet); 
    avcodec_close(codecContext); 
    avformat_close_input(&formatContext); 
    avformat_free_context(formatContext); 
    ALOGD("Read thread closed!"); 
} 

::私はsimpeテストコードを書い例えば enter image description here 、このビデオは私に次のログを提供します:

10-23 14:53:42.212 26970-4527/com.don.ffmpegplayer D/Player: Read thread started! 
10-23 14:53:42.212 26970-4527/com.don.ffmpegplayer D/Player: URL to play: http://www.ex.ua/load/280797285 
10-23 14:53:42.212 26970-4527/com.don.ffmpegplayer D/Player: formatContext allocated 
10-23 14:53:42.212 26970-4527/com.don.ffmpegplayer D/Player: frame allocated 
10-23 14:53:42.212 26970-4527/com.don.ffmpegplayer D/Player: frameRGBA allocated 
10-23 14:53:42.846 26970-4527/com.don.ffmpegplayer D/Player: formatContext opened 
10-23 14:53:42.879 26970-4527/com.don.ffmpegplayer D/Player: file info found 
10-23 14:53:42.879 26970-4527/com.don.ffmpegplayer D/Player: Stream [0]: type=VIDEO codecName=h264 
10-23 14:53:42.879 26970-4527/com.don.ffmpegplayer D/Player: Stream [1]: type=AUDIO codecName=ac3 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: Stream [2]: type=AUDIO codecName=ac3 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: Stream [3]: type=AUDIO codecName=ac3 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: Stream [4]: type=SUBTITLE codecName=subrip 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: Video stream index: 0 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: Codec found 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: Decoder found 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: codecContext created 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: codecContext params was set 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: Decoder opened 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: Window geometry changed 
10-23 14:53:42.880 26970-4527/com.don.ffmpegplayer D/Player: Video width: 1024 
                  Video height: 424 
10-23 14:53:42.882 26970-4527/com.don.ffmpegplayer D/Player: img2RGBAContext created 
10-23 14:53:42.882 26970-4527/com.don.ffmpegplayer D/Player: frameRGBABuffer size 868352 bytes 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer E/Player: Can not receive decoded frame yet 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.889 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.890 26970-4527/com.don.ffmpegplayer D/Player: Packet is not a video packet. Discard. 
10-23 14:53:42.899 26970-4527/com.don.ffmpegplayer E/Player: Can not receive decoded frame yet 
10-23 14:53:42.905 26970-4527/com.don.ffmpegplayer D/Player: Converting image to RGB565... 
10-23 14:53:42.918 26970-4527/com.don.ffmpegplayer D/Player: Image converted to RGB565 
10-23 14:53:42.919 26970-4527/com.don.ffmpegplayer D/Player: Image wrote into frameRGBABuffer 
10-23 14:53:42.920 26970-4527/com.don.ffmpegplayer D/Player: Writing 868352 bytes to windowBuffer 
10-23 14:53:42.921 26970-4527/com.don.ffmpegplayer D/Player: Image displayed 
10-23 14:53:42.926 26970-4527/com.don.ffmpegplayer D/Player: Converting image to RGB565... 
10-23 14:53:42.934 26970-4527/com.don.ffmpegplayer D/Player: Image converted to RGB565 
10-23 14:53:42.935 26970-4527/com.don.ffmpegplayer D/Player: Image wrote into frameRGBABuffer 
10-23 14:53:42.936 26970-4527/com.don.ffmpegplayer D/Player: Writing 868352 bytes to windowBuffer 
10-23 14:53:42.937 26970-4527/com.don.ffmpegplayer D/Player: Image displayed 

私が間違って何をしているのですか?私が正しく理解している場合、私は、次の手順を実行する必要があります。

  1. は、デコーダ
  2. からデコードAVFrameを取得
  3. は、ネイティブウィンドウにそれを書く変換されたフレームからRGB565またはRGB8888
  4. ゲット画素データにAVFrameデータを変換します

しかし、このコードでは2つの点が私を混乱させる:ANative_setBuffersGeometryは正しく呼び出さ、なぜframeRGBABufferサイズは868352バイトですか?ビデオサイズが1024 * 424 frameRGBABufferの場合、サイズはwidth*height*4でなければなりませんか?私がframeRGBABufferのサイズをwidth*height*4に変更すると、最初の画像が表示された後にプログラムがカースします。私はビデオdimmensionsをANative_setBuffersGeometryに渡します。

ご迷惑をおかけして申し訳ありません。

+0

ok、frameRGBbuffer sizeについて - RGB565が2バイト長であるため、正しいです。そのため、frameRGBabufferサイズはRGBA8888より2倍小さくなりますが、NativeWindowについての質問はまだ実際です。 – don11995

答えて

0

問題は、ビデオの幅と私がANativeWindow_setBuffersGeometryに渡す値にありました。私は理由はわかりませんが、ANativeWindow_setBuffersGeometryは、幅パラメータ、高さ - 任意のものとして640, 1280, 1920だけを修正することができます。私がスクリーンショットのような他の幅の問題のapperarsを設定した場合。