简体   繁体   English

Android AudioRecord 到 FFMPEG 编码原生 AAC

[英]Android AudioRecord to FFMPEG encode native AAC

I am doing video chatting in android and i would like to port ffmpeg to stream rtsp or rtmp but now i have a try in RTSP first.我正在 android 进行视频聊天,我想将 ffmpeg 移植到 stream rtsp 或 rtmp,但现在我先尝试使用 RTSP。 Somehow the problem now is av_write_frame or av_interleaved_write_frame is fail to work or just crash.不知何故,现在的问题是 av_write_frame 或 av_interleaved_write_frame 无法工作或只是崩溃。 Maybe... AudioRecord Sample format is not equals to FFMPEG setting Frame receive is not equals也许... AudioRecord Sample format is not equals to FFMPEG setting Frame receive is not equals

So code... AudioRecorder http://pastebin.com/iWtB3Jhy package com.curtis.broadcaster.Publisher;所以代码... AudioRecorder http://pastebin.com/iWtB3Jhy package com.curtis.broadcaster.Publisher;

import android.app.Activity;
import android.graphics.Bitmap;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.AudioRecord.OnRecordPositionUpdateListener;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;

public class Publisher extends Activity {
    private int mAudioBufferSize;
    private int mAudioBufferSampleSize;
    private AudioRecord mAudioRecord;
    private boolean inRecordMode = false;
    private short[] audioBuffer;
    private String Tag = "Publisher/Publisher.java";

    public void onCreate(Bundle savedInstanceState) {
        Log.i(Tag, "|| onCreate()");
        super.onCreate(savedInstanceState);
        initAudioRecord();
        Log.i(Tag, "-- End onCreate()");
    }

    @Override
    public void onResume() {
        Log.i(Tag, "|| onResume()");
        super.onResume();
        inRecordMode = true;
        Thread t = new Thread(new Runnable() {

            public void run() {
                Log.i(Tag, "|| Run Threat t");
                getSamples();
                Log.i(Tag, "-- End Threat t");
            }
        });
        t.start();
        Log.i(Tag, "-- End onResume()");
    }

    protected void onPause() {
        Log.i(Tag, "|| Run onPause()");
        inRecordMode = false;
        super.onPause();
        Log.i(Tag, "-- End onPause()");
    }

    @Override
    protected void onDestroy() {
        Log.i(Tag, "|| Run onDestroy()");
        if (mAudioRecord != null) {
            mAudioRecord.release();
            Log.i(Tag + " onDestroy", "mAudioRecord.release()");
        }
        jniStopAll();
        super.onDestroy();
        android.os.Process.killProcess(android.os.Process.myPid());
        Log.i(Tag, "-- End onDestroy()");
    }

    public OnRecordPositionUpdateListener mListener = new OnRecordPositionUpdateListener() {

        public void onPeriodicNotification(AudioRecord recorder) {
            Log.i(Tag + " mListener(onPeriodicNotification)", "time is "
                    + System.currentTimeMillis());
            jniSetAudioSample(audioBuffer);
        //  audioBuffer = new short[mAudioBufferSampleSize];
        }

        public void onMarkerReached(AudioRecord recorder) {
            Log.i(Tag + " mListener(onMarkerReached)",
                    "time is " + System.currentTimeMillis());
            inRecordMode = false;
            recorder.stop();
            Log.i(Tag, "recorder.stop()");
        }
    };

    private void initAudioRecord() {
        try {
            jniCheck();
            int sampleRate = 44100;
            int channelConfig = AudioFormat.CHANNEL_IN_MONO;
            int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
            mAudioBufferSize = 2 * AudioRecord.getMinBufferSize(sampleRate,
                    channelConfig, audioFormat);
            mAudioBufferSampleSize = mAudioBufferSize / 2;
            Log.i(Tag, "Buffer Size " + mAudioBufferSize);
            Log.i(Tag, "new AudioRecord begin");

            mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    sampleRate, channelConfig, audioFormat, mAudioBufferSize);
            Log.i(Tag, "new AudioRecord end");

            jniInitFFMpeg();
        } catch (IllegalArgumentException e) {
            Log.i(Tag, "initAudioRecord go Errors");
            e.printStackTrace();
        }

        // mAudioRecord.setNotificationMarkerPosition(10000);
        mAudioRecord.setPositionNotificationPeriod(1024);
        mAudioRecord.setRecordPositionUpdateListener(mListener);

        int audioRecordState = mAudioRecord.getState();
        if (audioRecordState != AudioRecord.STATE_INITIALIZED) {
            finish();
        }

    }

    private void getSamples() {
        Log.i(Tag, "|| getSamples()");
        if (mAudioRecord == null)
            return;

        audioBuffer = new short[mAudioBufferSampleSize];
        mAudioRecord.startRecording();
        int audioRecordingState = mAudioRecord.getRecordingState();
        if (audioRecordingState != AudioRecord.RECORDSTATE_RECORDING) {
            finish();
        }
        while (inRecordMode) {
            int samplesRead = mAudioRecord.read(audioBuffer, 0,
                    mAudioBufferSampleSize);
            Log.i(Tag, "getSamples >>SamplesRead : " + samplesRead);
        }
        mAudioRecord.stop();
        Log.i(Tag, "mAudioRecord.stop()");
    }

    private native void jniCheck();

    private native void jniInitFFMpeg();

    private native void jniSetAudioSample(short[] audioBuffer);

    private native void jniStopAll();

    static {
        System.loadLibrary("ffmpeg");
        System.loadLibrary("testerv4");

    }

}

FFMPEG JNI http://pastebin.com/hgPva35b FFMPEG JNI http://pastebin.com/hgPva35b

#include <jni.h>
#include <android/log.h>
#include <android/bitmap.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/time.h>
#include "libavformat/rtsp.h"

#include <libavutil/mathematics.h>
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libswscale/swscale.h>

#undef exit
/* Log System */
#define  LOG_TAG    "FFMPEGSample - v4a"
#define DEBUG_TAG   "FFMPEG-AUDIO PART"
#define  LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define  LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

/* 5 seconds stream duration */
#define STREAM_DURATION   5.0
#define STREAM_FRAME_RATE 25 /* 25 images/s */
#define STREAM_NB_FRAMES  ((int)(STREAM_DURATION * STREAM_FRAME_RATE))
#define STREAM_PIX_FMT      PIX_FMT_YUV420P /* default pix_fmt */
#define VIDEO_CODEC_ID      CODEC_ID_FLV1
#define AUDIO_CODEC_ID      CODEC_ID_AAC

static int sws_flags = SWS_BICUBIC;
int mode = 1; //1 = only audio, 2 = only video, 3 = both video and audio

AVFormatContext *avForCtx;
//AVFormatContext *oc;
AVStream *audio_st, *video_st;
double audio_pts, video_pts;
int frameCount, audioFrameCount, start;
char *url;

/*Audio Declare*/
float t, tincr, tincr2;
int16_t *samples;
uint8_t *audio_outbuf;
int audio_outbuf_size;
int audio_input_frame_size;

AVFormatContext *createAVFormatContext();
AVStream *add_audio_stream(AVFormatContext *oc, enum CodecID codec_id);
void open_video(AVFormatContext *oc, AVStream *st);
void open_audio(AVFormatContext *oc, AVStream *st);
AVStream *add_video_stream(AVFormatContext *oc, enum CodecID codec_id);
void write_audio_frame(AVFormatContext *oc, AVStream *st);
void write_video_frame(AVFormatContext *oc, AVStream *st);
void init();
void setAudioSample(unsigned char *inSample[]);
void stopAll();

/*/////////////////////////////////JNI Bridge////////////////////////////////////// */
void Java_com_curtis_broadcaster_Publisher_Publisher_jniCheck(JNIEnv* env,
        jobject this) {
    LOGI("-@ JNI work fine @-");
}
void Java_com_curtis_broadcaster_Publisher_Publisher_jniInitFFMpeg(JNIEnv* env,
        jobject this) {
    LOGI("-@ Init Encorder @-");

    /* initialize libavcodec, and register all codecs and formats */
    avcodec_init();
    avcodec_register_all();
    av_register_all();
    avformat_network_init(); //ERROR


    /* allocate the output media context */
    avForCtx = createAVFormatContext();
    frameCount = 1;
    audioFrameCount = 1;
    start = 0;

    /* add the audio and video streams using the default format codecs
     and initialize the codecs */
    video_st = NULL;
    audio_st = NULL;
    if (mode == 1 || mode == 3) {
        audio_st = add_audio_stream(avForCtx, AUDIO_CODEC_ID);
        LOGI("(Init Encorder) - addAudioStream");
    }
    if (mode == 2 || mode == 3) {
        video_st = add_video_stream(avForCtx, VIDEO_CODEC_ID);
        LOGI("(Init Encorder) - addVideoStream");

    }

    //  av_dump_format(avForCtx, 0, "rtsp://192.168.1.104/live/live", 1);
    LOGI("(Init Encorder) - Waiting to call open_*");

    if (audio_st) {
        open_audio(avForCtx, audio_st);
        LOGI("(Init Encorder) - open_audio");
    }

    if (video_st) {
        open_video(avForCtx, video_st);
        LOGI("(Init Encorder) - open_video");
    }

    av_write_header(avForCtx);
    LOGI("-@ Finish Init Encorder @-");

}

void Java_com_curtis_broadcaster_Publisher_Publisher_jniSetAudioSample(
        JNIEnv* env, jobject this, unsigned char *inSample[]) {
    if (audio_st) {
        LOGI("-@ Start setAudioSample @-");
        samples = (int16_t *) inSample;

        write_audio_frame(avForCtx, audio_st);
        LOGI("-@ Finish setAudioSample @-");
    }
}

void Java_com_curtis_broadcaster_Publisher_Publisher_jniStopAll(JNIEnv* env,
        jobject this) {
    LOGI("-@ Stopping All @-");
    //close_audio(avForCtx, audio_st);
    //close_video(avForCtx, video_st);
    LOGI("-@ Stopped All @-");
}
/*/////////////////////////////END JNI Bridge////////////////////////////////////// */

/* New Added Coding */
AVFormatContext *createAVFormatContext() {
    LOGI("-@OPEN - createAVFormatContext@-");

    AVFormatContext *ctx = avformat_alloc_context();
    //  ctx->oformat = av_guess_format("flv", "rtmp://192.168.1.104/live/live",
    //      NULL);
    //  ctx->oformat = av_guess_format("flv", NULL, NULL);

    //if (!av_guess_format("flv", NULL, NULL)) {

    //LOGI("-flv Can not Guess Format-");
    //}

    ctx->oformat = av_guess_format("rtsp", NULL, NULL);

    if (!av_guess_format("rtsp", NULL, NULL)) {

        LOGI("-flv Can not Guess Format-");
    }

    /*
     LOGI("%d",avformat_alloc_output_context2(&ctx, ctx->oformat, "flv",
     "rtmp://192.168.1.104/live/live"));
     if (!ctx) {
     LOGI("-@avformat_alloc_output_context2 fail@-");
     }*/
    //   LOGI("flv %d",avformat_alloc_output_context2(&ctx, ctx->oformat, "flv",
    //   "rtmp://192.168.1.104/live/live"));
    //   LOGI("rtmp %d",avformat_alloc_output_context2(&ctx, ctx->oformat, "rtmp",
    //   "rtmp://192.168.1.104/live/live"));
    //   LOGI("mpeg4 %d",avformat_alloc_output_context2(&ctx, ctx->oformat, "mpeg4",
    //   "rtmp://192.168.1.104/live/live"));
    //   LOGI("NULL %d",avformat_alloc_output_context2(&ctx, ctx->oformat, NULL,
    //   "rtmp://192.168.1.104/live/live"));
    avformat_alloc_output_context2(&ctx, ctx->oformat, "sdp",
            "rtsp://192.168.1.104:1935/live/live");

    if (!ctx) {
        LOGI("-@avformat_alloc_output_context2 fail@-");
    }

    LOGI("-@CLOSE - createAVFormatContext@-");

    return ctx;
}

/**************************************************************/
/* audio output */

/*
 * add an audio output stream
 */
AVStream *add_audio_stream(AVFormatContext *oc, enum CodecID codec_id) {
    LOGI("-@OPEN - add_audio_stream@-");

    AVCodecContext *c;
    AVStream *st = avformat_new_stream(oc, avcodec_find_encoder(codec_id));

    if (!st) {
        LOGI("-@add_audio_stream - Could not alloc stream@-");
        exit(1);
    }
    st->id = 1;

    c = st->codec;
    c->codec_id = AUDIO_CODEC_ID;
    c->codec_type = AVMEDIA_TYPE_AUDIO;

    /* put sample parameters */
    c->sample_fmt = AV_SAMPLE_FMT_FLT;
    //c->sample_fmt = AV_SAMPLE_FMT_S16;
    c->bit_rate = 100000;
    c->sample_rate = 44100;
    c->channels = 1;

    // some formats want stream headers to be separate
    if (oc->oformat->flags & AVFMT_GLOBALHEADER)
        c->flags |= CODEC_FLAG_GLOBAL_HEADER;
    LOGI("-@Close - add_audio_stream@-");

    return st;
}

void open_audio(AVFormatContext *oc, AVStream *st) {
    LOGI("@- open_audio -@");

    AVCodecContext *c;
    AVCodec *codec;

    c = st->codec;
    c->strict_std_compliance = -2;
    /* find the audio encoder */
    codec = avcodec_find_encoder(c->codec_id);
    if (!codec) {
        LOGI("@- open_audio E:codec not found-@");
        exit(1);
    }

    /* open it */
    if (avcodec_open(c, codec) < 0) {
        LOGI("%d",avcodec_open(c, codec));
        LOGI("@- open_audio E:could not open codec-@");
        exit(1);
    }

    /* init signal generator */
    t = 0;
    tincr = 2 * M_PI * 110.0 / c->sample_rate;
    /* increment frequency by 110 Hz per second */
    tincr2 = 2 * M_PI * 110.0 / c->sample_rate / c->sample_rate;

    audio_outbuf_size = 10000;
    audio_outbuf = av_malloc(audio_outbuf_size);

    /* ugly hack for PCM codecs (will be removed ASAP with new PCM
     support to compute the input frame size in samples */
    if (c->frame_size <= 1) {
        audio_input_frame_size = audio_outbuf_size / c->channels;
        switch (st->codec->codec_id) {
        case CODEC_ID_PCM_S16LE:
        case CODEC_ID_PCM_S16BE:
        case CODEC_ID_PCM_U16LE:
        case CODEC_ID_PCM_U16BE:
            audio_input_frame_size >>= 1;
            break;
        default:
            break;
        }
    } else {
        audio_input_frame_size = c->frame_size;
    }
    LOGI("audio_input_frame_size : %d",audio_input_frame_size);
    samples = av_malloc(audio_input_frame_size * 2 * c->channels);
    LOGI("@- Close open_audio -@");

}

/* prepare a 16 bit dummy audio frame of 'frame_size' samples and
 'nb_channels' channels */
void get_audio_frame(int16_t *samples, int frame_size, int nb_channels) {
    LOGI("@- get_audio_frame -@");

    int j, i, v;
    int16_t *q;

    q = samples;
    for (j = 0; j < frame_size; j++) {
        v = (int) (sin(t) * 10000);
        for (i = 0; i < nb_channels; i++)
            *q++ = v;
        t += tincr;
        tincr += tincr2;
        LOGI("@- audio_frame Looping -@");
    }
    LOGI("@- CLOSE get_audio_frame -@");

}

void write_audio_frame(AVFormatContext *oc, AVStream *st) {
    LOGI("@- write_audio_frame -@");

    AVCodecContext *c;
    AVPacket pkt;
    av_init_packet(&pkt);

    c = st->codec;

    //get_audio_frame(samples, audio_input_frame_size, c->channels);
    LOGI("@- write_audio_frame : got frame from get_audio_frame -@");

    pkt.size
            = avcodec_encode_audio(c, audio_outbuf, audio_outbuf_size, samples);
    LOGI("%d",pkt.size);

    if (c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE)
        pkt.pts
                = av_rescale_q(c->coded_frame->pts, c->time_base, st->time_base);
    LOGI("%d",pkt.pts);

    pkt.flags |= AV_PKT_FLAG_KEY;
    pkt.stream_index = st->index;
    pkt.data = audio_outbuf;
    LOGI("Finish PKT");

    /* write the compressed frame in the media file */
    //  if (av_interleaved_write_frame(oc, &pkt) != 0) {
    //  LOGI("@- write_audio_frame E:Error while writing audio frame -@");
    //  exit(1);
    //  }

    if (av_interleaved_write_frame(oc, &pkt) != 0) {
        LOGI("Error while writing audio frame %d\n", audioFrameCount);
    } else {
        LOGI("Writing Audio Frame %d", audioFrameCount);
    }

    LOGI("@- CLOSE write_audio_frame -@");
    audioFrameCount++;
    av_free_packet(&pkt);
}

void close_audio(AVFormatContext *oc, AVStream *st) {
    avcodec_close(st->codec);

    av_free(samples);
    av_free(audio_outbuf);
}

/**************************************************************/
/* video output */

AVFrame *picture, *tmp_picture;
uint8_t *video_outbuf;
int frame_count, video_outbuf_size;

/* add a video output stream */
AVStream *add_video_stream(AVFormatContext *oc, enum CodecID codec_id) {
    AVCodecContext *c;
    AVStream *st;
    AVCodec *codec;

    st = avformat_new_stream(oc, NULL);
    if (!st) {
        fprintf(stderr, "Could not alloc stream\n");
        exit(1);
    }

    c = st->codec;

    /* find the video encoder */
    codec = avcodec_find_encoder(codec_id);
    if (!codec) {
        fprintf(stderr, "codec not found\n");
        exit(1);
    }
    avcodec_get_context_defaults3(c, codec);

    c->codec_id = codec_id;

    /* put sample parameters */
    c->bit_rate = 400000;
    /* resolution must be a multiple of two */
    c->width = 352;
    c->height = 288;
    /* time base: this is the fundamental unit of time (in seconds) in terms
     of which frame timestamps are represented. for fixed-fps content,
     timebase should be 1/framerate and timestamp increments should be
     identically 1. */
    c->time_base.den = STREAM_FRAME_RATE;
    c->time_base.num = 1;
    c->gop_size = 12; /* emit one intra frame every twelve frames at most */
    c->pix_fmt = STREAM_PIX_FMT;
    if (c->codec_id == CODEC_ID_MPEG2VIDEO) {
        /* just for testing, we also add B frames */
        c->max_b_frames = 2;
    }
    if (c->codec_id == CODEC_ID_MPEG1VIDEO) {
        /* Needed to avoid using macroblocks in which some coeffs overflow.
         This does not happen with normal video, it just happens here as
         the motion of the chroma plane does not match the luma plane. */
        c->mb_decision = 2;
    }
    // some formats want stream headers to be separate
    if (oc->oformat->flags & AVFMT_GLOBALHEADER)
        c->flags |= CODEC_FLAG_GLOBAL_HEADER;

    return st;
}

AVFrame *alloc_picture(enum PixelFormat pix_fmt, int width, int height) {
    AVFrame * picture;
    uint8_t *picture_buf;
    int size;

    picture = avcodec_alloc_frame();
    if (!picture)
        return NULL;
    size = avpicture_get_size(pix_fmt, width, height);
    picture_buf = av_malloc(size);
    if (!picture_buf) {
        av_free(picture);
        return NULL;
    }
    avpicture_fill((AVPicture *) picture, picture_buf, pix_fmt, width, height);
    return picture;
}

void open_video(AVFormatContext *oc, AVStream *st) {
    AVCodec *codec;
    AVCodecContext *c;

    c = st->codec;

    /* find the video encoder */
    codec = avcodec_find_encoder(c->codec_id);
    if (!codec) {
        fprintf(stderr, "codec not found\n");
        exit(1);
    }

    /* open the codec */
    if (avcodec_open(c, codec) < 0) {
        fprintf(stderr, "could not open codec\n");
        exit(1);
    }

    video_outbuf = NULL;
    if (!(oc->oformat->flags & AVFMT_RAWPICTURE)) {
        /* allocate output buffer */
        /* XXX: API change will be done */
        /* buffers passed into lav* can be allocated any way you prefer,
         as long as they're aligned enough for the architecture, and
         they're freed appropriately (such as using av_free for buffers
         allocated with av_malloc) */
        video_outbuf_size = 200000;
        video_outbuf = av_malloc(video_outbuf_size);
    }

    /* allocate the encoded raw picture */
    picture = alloc_picture(c->pix_fmt, c->width, c->height);
    if (!picture) {
        fprintf(stderr, "Could not allocate picture\n");
        exit(1);
    }

    /* if the output format is not YUV420P, then a temporary YUV420P
     picture is needed too. It is then converted to the required
     output format */
    tmp_picture = NULL;
    if (c->pix_fmt != PIX_FMT_YUV420P) {
        tmp_picture = alloc_picture(PIX_FMT_YUV420P, c->width, c->height);
        if (!tmp_picture) {
            fprintf(stderr, "Could not allocate temporary picture\n");
            exit(1);
        }
    }
}

/* prepare a dummy image */
void fill_yuv_image(AVFrame *pict, int frame_index, int width, int height) {
    int x, y, i;

    i = frame_index;

    /* Y */
    for (y = 0; y < height; y++) {
        for (x = 0; x < width; x++) {
            pict->data[0][y * pict->linesize[0] + x] = x + y + i * 3;
        }
    }

    /* Cb and Cr */
    for (y = 0; y < height / 2; y++) {
        for (x = 0; x < width / 2; x++) {
            pict->data[1][y * pict->linesize[1] + x] = 128 + y + i * 2;
            pict->data[2][y * pict->linesize[2] + x] = 64 + x + i * 5;
        }
    }
}

void write_video_frame(AVFormatContext *oc, AVStream *st) {
    int out_size, ret;
    AVCodecContext *c;
    struct SwsContext *img_convert_ctx;

    c = st->codec;

    if (frame_count >= STREAM_NB_FRAMES) {
        /* no more frame to compress. The codec has a latency of a few
         frames if using B frames, so we get the last frames by
         passing the same picture again */
    } else {
        if (c->pix_fmt != PIX_FMT_YUV420P) {
            /* as we only generate a YUV420P picture, we must convert it
             to the codec pixel format if needed */
            if (img_convert_ctx == NULL) {
                img_convert_ctx = sws_getContext(c->width, c->height,
                        PIX_FMT_YUV420P, c->width, c->height, c->pix_fmt,
                        sws_flags, NULL, NULL, NULL);
                if (img_convert_ctx == NULL) {
                    fprintf(stderr,
                            "Cannot initialize the conversion context\n");
                    exit(1);
                }
            }
            fill_yuv_image(tmp_picture, frame_count, c->width, c->height);
            sws_scale(img_convert_ctx, tmp_picture->data,
                    tmp_picture->linesize, 0, c->height, picture->data,
                    picture->linesize);
        } else {
            fill_yuv_image(picture, frame_count, c->width, c->height);
        }
    }

    if (oc->oformat->flags & AVFMT_RAWPICTURE) {
        /* raw video case. The API will change slightly in the near
         future for that. */
        AVPacket pkt;
        av_init_packet(&pkt);

        pkt.flags |= AV_PKT_FLAG_KEY;
        pkt.stream_index = st->index;
        pkt.data = (uint8_t *) picture;
        pkt.size = sizeof(AVPicture);

        ret = av_interleaved_write_frame(oc, &pkt);
    } else {
        /* encode the image */
        out_size = avcodec_encode_video(c, video_outbuf, video_outbuf_size,
                picture);
        /* if zero size, it means the image was buffered */
        if (out_size > 0) {
            AVPacket pkt;
            av_init_packet(&pkt);

            if (c->coded_frame->pts != AV_NOPTS_VALUE)
                pkt.pts = av_rescale_q(c->coded_frame->pts, c->time_base,
                        st->time_base);
            if (c->coded_frame->key_frame)
                pkt.flags |= AV_PKT_FLAG_KEY;
            pkt.stream_index = st->index;
            pkt.data = video_outbuf;
            pkt.size = out_size;

            /* write the compressed frame in the media file */
            ret = av_interleaved_write_frame(oc, &pkt);
        } else {
            ret = 0;
        }
    }
    if (ret != 0) {
        fprintf(stderr, "Error while writing video frame\n");
        exit(1);
    }
    frame_count++;
}

void close_video(AVFormatContext *oc, AVStream *st) {
    avcodec_close(st->codec);
    av_free(picture->data[0]);
    av_free(picture);
    if (tmp_picture) {
        av_free(tmp_picture->data[0]);
        av_free(tmp_picture);
    }
    av_free(video_outbuf);
}

Android Manifest has been set and init everything. Android 清单已设置并初始化所有内容。 Please give me some ideas.. Some log message to yours http://pastebin.com/uPD5LyH2请给我一些想法.. 一些日志消息给你的 http://pastebin.com/uPD5LyH2

I know its probably too late to answer this question but just in case if it helps you or someone else who stumbles upon the same question in the future, here's a workaround.我知道现在回答这个问题可能为时已晚,但以防万一它对您或将来偶然发现相同问题的其他人有帮助,这里有一个解决方法。

I had been working on a similar kind of project but the difference is that rather than using JNI and compiled Native FFmpeg Shared Libraries, I opted for a compiled native binary and used the Java Process API to communicate with the binary.我一直在从事类似的项目,但不同之处在于,我没有使用 JNI 和编译的本机 FFmpeg 共享库,而是选择了编译的本机二进制文件并使用 Java 进程 API 与二进制文件进行通信。

FFmpeg needs to be prompted of the nature of the incoming data. FFmpeg 需要提示传入数据的性质。 The audio frame created by AudioRecord is PCM - 16 bit encoded, and you don't seem to have specified the format of the incoming audio stream FFmpeg. AudioRecord创建的音频帧是 PCM - 16 位编码的,您似乎没有指定传入音频的格式 stream FFmpeg。

The command issued to ffmpeg could be as follows:向 ffmpeg 发出的命令可能如下:

ffmpeg -f u16le -acodec pcm_s16le -i - -acodec <output-file-codec> <rtsp-stream-address>

The audio data received from the audio source was written to the input stream of the FFmpeg process.从音频源接收到的音频数据被写入 FFmpeg 进程的输入 stream。

The audio data could also be streamed to ffmpeg through a pipe. ParcelFileDescriptor.createPipe() could be used to create pipes on the Android Platform and the command line replacement for -i - would be -i pipe:<fd> where fd is the file descriptor of the read side of the created pipe.音频数据也可以通过 pipe 流式传输到ParcelFileDescriptor.createPipe()可用于在 Android 平台上创建管道,-i 的命令行替换为-i - -i pipe:<fd>其中fd是创建的 pipe 读取端的文件描述符。

I'd rather suggest to access ffmpeg through command line interface rather than using JNI, as it is well documented and could also be beneficial in detecting the problem using the debug log level.我宁愿建议通过命令行界面而不是使用 JNI 来访问 ffmpeg,因为它有很好的文档记录并且也可能有助于使用调试日志级别检测问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM