提交 83c6bb23 authored 作者: autulin's avatar autulin

1.适配32位机型

2.停止录制优化 todo:视频大小控制
上级 2652cbf3
...@@ -10,6 +10,7 @@ extern "C" ...@@ -10,6 +10,7 @@ extern "C"
} }
#include "threadsafe_queue.cpp" #include "threadsafe_queue.cpp"
#include "log.h"
#include <jni.h> #include <jni.h>
#include <string> #include <string>
...@@ -37,19 +38,20 @@ extern "C" ...@@ -37,19 +38,20 @@ extern "C"
using namespace std; using namespace std;
static long getCurrentTime() { static uint64_t getCurrentTime() {
struct timeval tv; struct timeval tv;
gettimeofday(&tv,NULL); gettimeofday(&tv,NULL);
return tv.tv_sec * 1000 + tv.tv_usec / 1000; return (int64_t)tv.tv_sec * 1000 + tv.tv_usec / 1000;
} }
static long bytes2long(char b[]) { static uint64_t bytes2long(uint8_t b[]) {
long temp = 0; uint64_t temp = 0;
long res = 0; uint64_t res = 0;
for (int i=0;i<8;i++) { for (int i=0;i<8;i++) {
res <<= 8; res <<= 8;
temp = b[i] & 0xff; temp = b[i];
temp = temp & 0xff;
res |= temp; res |= temp;
} }
return res; return res;
......
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
* s64Src [in] 时间戳 * s64Src [in] 时间戳
*@return: 0 success, others failed *@return: 0 success, others failed
*/ */
int gb28181_make_ps_header(char *pData, unsigned long long s64Scr) int gb28181_make_ps_header(char *pData, int64_t s64Scr)
{ {
unsigned long long lScrExt = 0; //(s64Scr) % 100; int64_t lScrExt = 0; //(s64Scr) % 100;
// s64Scr = s64Scr * 3600; // / 100; // 90000/fps // s64Scr = s64Scr * 3600; // / 100; // 90000/fps
// 这里除以100是由于sdp协议返回的video的频率是90000,帧率是25帧/s,所以每次递增的量是3600, // 这里除以100是由于sdp协议返回的video的频率是90000,帧率是25帧/s,所以每次递增的量是3600,
// 所以实际你应该根据你自己编码里的时间戳来处理以保证时间戳的增量为3600即可, // 所以实际你应该根据你自己编码里的时间戳来处理以保证时间戳的增量为3600即可,
...@@ -141,7 +141,7 @@ int gb28181_make_psm_header(char *pData) ...@@ -141,7 +141,7 @@ int gb28181_make_psm_header(char *pData)
* dts [in] * dts [in]
*@return: 0 success, others failed *@return: 0 success, others failed
*/ */
int gb28181_make_pes_header(char *pData, int stream_id, int payload_len, unsigned long long pts, unsigned long long dts) int gb28181_make_pes_header(char *pData, int stream_id, int payload_len, int64_t pts, int64_t dts)
{ {
bits_buffer_t bitsBuffer; bits_buffer_t bitsBuffer;
...@@ -196,7 +196,7 @@ int gb28181_make_pes_header(char *pData, int stream_id, int payload_len, unsigne ...@@ -196,7 +196,7 @@ int gb28181_make_pes_header(char *pData, int stream_id, int payload_len, unsigne
*@param : pData [in] 填充ps头数据的地址 *@param : pData [in] 填充ps头数据的地址
*@return: 0 success, others failed *@return: 0 success, others failed
*/ */
int gb28181_make_rtp_header(char *pData, int seqNum, unsigned long long timestamp, int ssrc ) int gb28181_make_rtp_header(char *pData, int seqNum, int64_t timestamp, int ssrc )
{ {
bits_buffer_t bitsBuffer; bits_buffer_t bitsBuffer;
......
...@@ -47,13 +47,25 @@ int GB28181Muxer::initMuxer() { ...@@ -47,13 +47,25 @@ int GB28181Muxer::initMuxer() {
pCodecCtx->height = arguments->out_width; pCodecCtx->height = arguments->out_width;
} }
LOGI("in height: %d, in width: %d.\n out height: %d, out width: %d. \n context height: %d, context width: %d \n video bitrate:%lld, video framerate:%d,\n custom_format %d",
arguments->in_height,
arguments->in_width,
arguments->out_height,
arguments->out_width,
pCodecCtx->height,
pCodecCtx->width,
arguments->video_bit_rate,
arguments->video_frame_rate,
arguments->v_custom_format
)
pCodecCtx->bit_rate = arguments->video_bit_rate; pCodecCtx->bit_rate = arguments->video_bit_rate;
//这里是设置关键帧的间隔 //这里是设置关键帧的间隔
pCodecCtx->gop_size = 25; pCodecCtx->gop_size = 25;
pCodecCtx->thread_count = 12; pCodecCtx->thread_count = 12;
pCodecCtx->time_base.num = 1; pCodecCtx->time_base.num = 1;
pCodecCtx->time_base.den = arguments->frame_rate; pCodecCtx->time_base.den = arguments->video_frame_rate;
// pCodecCtx->me_pre_cmp = 1; // pCodecCtx->me_pre_cmp = 1;
//H264 //H264
//pCodecCtx->me_range = 16; //pCodecCtx->me_range = 16;
...@@ -149,35 +161,25 @@ int GB28181Muxer::sendAudioFrame(uint8_t *buf) { ...@@ -149,35 +161,25 @@ int GB28181Muxer::sendAudioFrame(uint8_t *buf) {
void *GB28181Muxer::startMux(void *obj) { void *GB28181Muxer::startMux(void *obj) {
LOGE("start mux thread"); LOGE("start mux thread");
GB28181Muxer *gb28181Muxer = (GB28181Muxer *) obj; GB28181Muxer *gb28181Muxer = (GB28181Muxer *) obj;
while (!gb28181Muxer->is_end || !gb28181Muxer->video_queue.empty()) { while (!gb28181Muxer->is_end) {
if (gb28181Muxer->is_release) {
LOGE("release data")
//Clean
if (gb28181Muxer->video_st) {
avcodec_close(gb28181Muxer->video_st->codec);
av_free(gb28181Muxer->pFrame);
}
avformat_free_context(gb28181Muxer->pFormatCtx);
delete gb28181Muxer;
return 0;
}
if (gb28181Muxer->video_queue.empty()) { if (gb28181Muxer->video_queue.empty()) {
continue; continue;
} }
uint8_t *picture_buf = *gb28181Muxer->video_queue.wait_and_pop().get(); uint8_t *picture_buf = *gb28181Muxer->video_queue.wait_and_pop().get();
long v_time = bytes2long(reinterpret_cast<char *>(picture_buf)); int64_t v_time = bytes2long(picture_buf);
int in_y_size = gb28181Muxer->arguments->in_width * gb28181Muxer->arguments->in_height; int in_y_size = gb28181Muxer->arguments->in_width * gb28181Muxer->arguments->in_height;
// 处理视频帧并到 h264_encoder->pFrame 中 // 处理视频帧并到 h264_encoder->pFrame 中
gb28181Muxer->custom_filter(gb28181Muxer, picture_buf + 8, in_y_size, gb28181Muxer->custom_filter(gb28181Muxer, picture_buf + 8, in_y_size,
gb28181Muxer->arguments->v_custom_format); gb28181Muxer->arguments->v_custom_format);
delete (picture_buf);
long lastPTS = gb28181Muxer->pFrame->pts; int64_t lastPTS = gb28181Muxer->pFrame->pts;
if (gb28181Muxer->startTime == 0) gb28181Muxer->startTime = v_time; if (gb28181Muxer->startTime == 0) gb28181Muxer->startTime = v_time;
gb28181Muxer->pFrame->pts = (v_time - gb28181Muxer->startTime) * 90; gb28181Muxer->pFrame->pts = (v_time - gb28181Muxer->startTime) * 90;
LOGE("v_time:%ld, now:%ld, lastPTS: %ld, new PTS: %ld, divid: %ld", v_time, LOGE("v_time:%lld,startTime: %lld, now:%lld, lastPTS: %lld, new PTS: %lld, divid: %lld", v_time,
getCurrentTime(), lastPTS, gb28181Muxer->pFrame->pts, gb28181Muxer->startTime, getCurrentTime(), lastPTS, gb28181Muxer->pFrame->pts,
gb28181Muxer->pFrame->pts - lastPTS); gb28181Muxer->pFrame->pts - lastPTS);
gb28181Muxer->videoFrameCnt++; gb28181Muxer->videoFrameCnt++;
int got_picture = 0; int got_picture = 0;
...@@ -192,10 +194,9 @@ void *GB28181Muxer::startMux(void *obj) { ...@@ -192,10 +194,9 @@ void *GB28181Muxer::startMux(void *obj) {
if (got_picture == 1) { if (got_picture == 1) {
gb28181Muxer->mux(gb28181Muxer); gb28181Muxer->mux(gb28181Muxer);
} }
delete (picture_buf);
} }
if (gb28181Muxer->is_end) { if (gb28181Muxer->is_end) {
gb28181Muxer->encodeEnd(); gb28181Muxer->endMux();
delete gb28181Muxer; delete gb28181Muxer;
} }
return 0; return 0;
...@@ -318,8 +319,8 @@ GB28181Muxer::custom_filter(const GB28181Muxer *gb28181Muxer, const uint8_t *pic ...@@ -318,8 +319,8 @@ GB28181Muxer::custom_filter(const GB28181Muxer *gb28181Muxer, const uint8_t *pic
* 视频编码结束 * 视频编码结束
* @return * @return
*/ */
int GB28181Muxer::encodeEnd() { int GB28181Muxer::endMux() {
LOGE("endMux");
closeOutput(); closeOutput();
LOGE("aduio queue left num: %d, video queue left num: %d", audio_queue.size(), video_queue.size()); LOGE("aduio queue left num: %d, video queue left num: %d", audio_queue.size(), video_queue.size());
...@@ -339,24 +340,19 @@ int GB28181Muxer::encodeEnd() { ...@@ -339,24 +340,19 @@ int GB28181Muxer::encodeEnd() {
} }
/** /**
* 用户中断 * 用户结束
*/ */
void GB28181Muxer::user_end() { void GB28181Muxer::user_end() {
LOGE("call user end"); LOGE("call user end");
is_end = END_STATE; is_end = END_STATE;
} }
void GB28181Muxer::release() {
is_release = RELEASE_TRUE;
}
int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) { int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) {
long lastPts = gb28181Muxer->pkt.pts; int64_t lastPts = gb28181Muxer->pkt.pts;
gb28181Muxer->nowPkt = &gb28181Muxer->pkt; gb28181Muxer->nowPkt = &gb28181Muxer->pkt;
int append = 0; int64_t append = 0;
int cnt = 0; int cnt = 0;
while (!gb28181Muxer->is_end || !gb28181Muxer->video_queue.empty()) { while (!gb28181Muxer->is_end) {
char szTempPacketHead[256]; char szTempPacketHead[256];
int nSizePos = 0; int nSizePos = 0;
int nSize = 0; int nSize = 0;
...@@ -364,12 +360,14 @@ int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) { ...@@ -364,12 +360,14 @@ int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) {
// read next frame // read next frame
uint8_t *picture_buf = *gb28181Muxer->video_queue.wait_and_pop().get(); uint8_t *picture_buf = *gb28181Muxer->video_queue.wait_and_pop().get();
long v_time = bytes2long(reinterpret_cast<char *>(picture_buf)); int64_t v_time = bytes2long(picture_buf);
int in_y_size = gb28181Muxer->arguments->in_width * gb28181Muxer->arguments->in_height; int in_y_size = gb28181Muxer->arguments->in_width * gb28181Muxer->arguments->in_height;
gb28181Muxer->custom_filter(gb28181Muxer, picture_buf + 8, in_y_size, gb28181Muxer->custom_filter(gb28181Muxer, picture_buf + 8, in_y_size,
gb28181Muxer->arguments->v_custom_format); gb28181Muxer->arguments->v_custom_format);
delete(picture_buf);
gb28181Muxer->pFrame->pts = (v_time - gb28181Muxer->startTime) * 90; gb28181Muxer->pFrame->pts = (v_time - gb28181Muxer->startTime) * 90;
LOGE("get a pts:%ld", gb28181Muxer->pFrame->pts); LOGE("v_time: %lld, get a pts:%lld (aduio queue left num: %d, video queue left num: %d)"
, v_time, gb28181Muxer->pFrame->pts, audio_queue.size(), video_queue.size());
int got_picture; int got_picture;
int ret = avcodec_encode_video2(gb28181Muxer->pCodecCtx, gb28181Muxer->nextPkt, int ret = avcodec_encode_video2(gb28181Muxer->pCodecCtx, gb28181Muxer->nextPkt,
...@@ -379,12 +377,12 @@ int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) { ...@@ -379,12 +377,12 @@ int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) {
} }
// 读到了下一帧 // 读到了下一帧
long newPts = gb28181Muxer->nextPkt->pts; int64_t newPts = gb28181Muxer->nextPkt->pts;
// 计算写入音频的个数 // 计算写入音频的个数
int frameDiv = newPts - lastPts; int64_t frameDiv = newPts - lastPts;
append = (frameDiv + append) % 3600; append = (frameDiv + append) % 3600;
int audioCnt = (frameDiv + append) / 3600; int audioCnt = (frameDiv + append) / 3600;
LOGE("now pts:%ld.|%ld| next pts:%ld,audio count:%d", LOGE("now pts:%lld.|%lld| next pts:%lld,audio count:%d",
gb28181Muxer->nowPkt->pts, gb28181Muxer->nowPkt->pts,
gb28181Muxer->nextPkt->pts - gb28181Muxer->nowPkt->pts, gb28181Muxer->nextPkt->pts - gb28181Muxer->nowPkt->pts,
gb28181Muxer->nextPkt->pts, audioCnt); gb28181Muxer->nextPkt->pts, audioCnt);
...@@ -420,11 +418,9 @@ int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) { ...@@ -420,11 +418,9 @@ int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) {
gb28181Muxer->nextPkt = t; gb28181Muxer->nextPkt = t;
// LOGE("now frame:%ld", h264_encoder->nowPkt->pts); // LOGE("now frame:%ld", h264_encoder->nowPkt->pts);
while (audioCnt > 0) { while (audioCnt > 0) {
uint8_t *audioFrame = *gb28181Muxer->audio_queue.wait_and_pop().get(); uint8_t *audioFrame = *gb28181Muxer->audio_queue.wait_and_pop().get();
long audioPts = gb28181Muxer->audioFrameCnt * (90000 / gb28181Muxer->arguments->frame_rate); int64_t audioPts = gb28181Muxer->audioFrameCnt * 3600; // 音频默认25帧,90000/25=3600
int aFrameLen = gb28181Muxer->arguments->a_frame_len / 2; int aFrameLen = gb28181Muxer->arguments->a_frame_len / 2;
gb28181_make_pes_header(szTempPacketHead + nSizePos, 0xC0, aFrameLen, audioPts, gb28181_make_pes_header(szTempPacketHead + nSizePos, 0xC0, aFrameLen, audioPts,
audioPts); audioPts);
...@@ -436,6 +432,8 @@ int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) { ...@@ -436,6 +432,8 @@ int GB28181Muxer::mux(GB28181Muxer *gb28181Muxer) {
delete (audioFrame); delete (audioFrame);
} }
} }
LOGE("mux over!");
return 0;
} }
void GB28181Muxer::initOutput() { void GB28181Muxer::initOutput() {
......
...@@ -27,9 +27,7 @@ public: ...@@ -27,9 +27,7 @@ public:
void user_end(); void user_end();
void release(); int endMux();
int encodeEnd();
void custom_filter(const GB28181Muxer *gb28181Muxer, const uint8_t *picture_buf, void custom_filter(const GB28181Muxer *gb28181Muxer, const uint8_t *picture_buf,
int in_y_size, int in_y_size,
...@@ -60,7 +58,7 @@ private: ...@@ -60,7 +58,7 @@ private:
int out_y_size; int out_y_size;
int audioFrameCnt = 0; int audioFrameCnt = 0;
int videoFrameCnt = 0; int videoFrameCnt = 0;
long startTime = 0; int64_t startTime = 0;
ofstream fout; ofstream fout;
......
...@@ -55,7 +55,7 @@ Java_com_autulin_gb28181library_JNIBridge_initMuxer(JNIEnv *env, jclass type, js ...@@ -55,7 +55,7 @@ Java_com_autulin_gb28181library_JNIBridge_initMuxer(JNIEnv *env, jclass type, js
strcat(arguments->media_path, MEDIA_FORMAT); strcat(arguments->media_path, MEDIA_FORMAT);
arguments->video_bit_rate = bit_rate; arguments->video_bit_rate = bit_rate;
arguments->frame_rate = frameRate; arguments->video_frame_rate = frameRate;
arguments->in_width = in_width; arguments->in_width = in_width;
arguments->in_height = in_height; arguments->in_height = in_height;
arguments->out_height = out_height; arguments->out_height = out_height;
...@@ -105,16 +105,3 @@ Java_com_autulin_gb28181library_JNIBridge_endMux(JNIEnv *env, jclass type) { ...@@ -105,16 +105,3 @@ Java_com_autulin_gb28181library_JNIBridge_endMux(JNIEnv *env, jclass type) {
} }
return 0; return 0;
} }
extern "C"
JNIEXPORT jint JNICALL
Java_com_autulin_gb28181library_JNIBridge_release(JNIEnv *env, jclass type) {
if (gb28181Muxer != NULL) {
try {
gb28181Muxer->release();
}catch (exception e){}
gb28181Muxer = NULL;
}
return 0;
}
\ No newline at end of file
...@@ -16,8 +16,8 @@ typedef struct UserArguments { ...@@ -16,8 +16,8 @@ typedef struct UserArguments {
int in_height; //输入高度 int in_height; //输入高度
int out_height; //输出高度 int out_height; //输出高度
int out_width; //输出宽度 int out_width; //输出宽度
int frame_rate; //视频帧率控制 int video_frame_rate; //视频帧率控制
long long video_bit_rate; //视频比特率控制 int64_t video_bit_rate; //视频比特率控制
int v_custom_format; //一些滤镜操作控制 int v_custom_format; //一些滤镜操作控制
int a_frame_len; int a_frame_len;
JNIEnv *env; //env全局指针 JNIEnv *env; //env全局指针
......
...@@ -86,7 +86,8 @@ public class DemoActivity extends AppCompatActivity implements ...@@ -86,7 +86,8 @@ public class DemoActivity extends AppCompatActivity implements
mMediaRecorder.setOnPreparedListener(this); mMediaRecorder.setOnPreparedListener(this);
// 设置输出 // 设置输出
String fileName = String.valueOf(System.currentTimeMillis()); // String fileName = String.valueOf(System.currentTimeMillis());
String fileName = "tttttt";
mediaOutput = mMediaRecorder.setFileOutPut(fileName); mediaOutput = mMediaRecorder.setFileOutPut(fileName);
mMediaRecorder.setSurfaceHolder(mSurfaceView.getHolder()); mMediaRecorder.setSurfaceHolder(mSurfaceView.getHolder());
......
...@@ -74,6 +74,4 @@ public class JNIBridge { ...@@ -74,6 +74,4 @@ public class JNIBridge {
public static native int endMux(); public static native int endMux();
public static native int release();
} }
...@@ -410,6 +410,11 @@ public abstract class MediaRecorderBase implements Callback, PreviewCallback, IM ...@@ -410,6 +410,11 @@ public abstract class MediaRecorderBase implements Callback, PreviewCallback, IM
public void endMux() { public void endMux() {
mRecording = false; mRecording = false;
// 停止音频录制
if (mAudioCollector != null) {
mAudioCollector.interrupt();
mAudioCollector = null;
}
} }
...@@ -430,6 +435,15 @@ public abstract class MediaRecorderBase implements Callback, PreviewCallback, IM ...@@ -430,6 +435,15 @@ public abstract class MediaRecorderBase implements Callback, PreviewCallback, IM
return; return;
List<Integer> rates = mParameters.getSupportedPreviewFrameRates(); List<Integer> rates = mParameters.getSupportedPreviewFrameRates();
Log.e("MedidaRecord", "支持的帧率有 "+ rates.toString()); Log.e("MedidaRecord", "支持的帧率有 "+ rates.toString());
StringBuilder sb = new StringBuilder();
for (Size size:
mSupportedPreviewSizes) {
sb.append(size.width);
sb.append('x');
sb.append(size.height);
sb.append(',');
}
Log.e("MedidaRecord", "支持的预览大小有(宽x高):"+ sb.toString());
if (rates != null) { if (rates != null) {
if (rates.contains(MAX_FRAME_RATE)) { if (rates.contains(MAX_FRAME_RATE)) {
mFrameRate = MAX_FRAME_RATE; mFrameRate = MAX_FRAME_RATE;
...@@ -471,6 +485,7 @@ public abstract class MediaRecorderBase implements Callback, PreviewCallback, IM ...@@ -471,6 +485,7 @@ public abstract class MediaRecorderBase implements Callback, PreviewCallback, IM
SMALL_VIDEO_HEIGHT = 480; SMALL_VIDEO_HEIGHT = 480;
} }
mParameters.setPreviewSize(mSupportedPreviewWidth, SMALL_VIDEO_HEIGHT); mParameters.setPreviewSize(mSupportedPreviewWidth, SMALL_VIDEO_HEIGHT);
Log.e("MedidaRecord", "最终选择预览大小:"+ mSupportedPreviewWidth+"x"+SMALL_VIDEO_HEIGHT);
// 设置输出视频流尺寸,采样率 // 设置输出视频流尺寸,采样率
mParameters.setPreviewFormat(ImageFormat.YV12); mParameters.setPreviewFormat(ImageFormat.YV12);
...@@ -606,7 +621,7 @@ public abstract class MediaRecorderBase implements Callback, PreviewCallback, IM ...@@ -606,7 +621,7 @@ public abstract class MediaRecorderBase implements Callback, PreviewCallback, IM
*/ */
public void release() { public void release() {
JNIBridge.release(); JNIBridge.endMux();
// 停止视频预览 // 停止视频预览
stopPreview(); stopPreview();
// 停止音频录制 // 停止音频录制
......
# Project-wide Gradle settings. ## Project-wide Gradle settings.
# IDE (e.g. Android Studio) users: #
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit # For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html # http://www.gradle.org/docs/current/userguide/build_environment.html
#
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m # Default value: -Xmx1024m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
#
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true # org.gradle.parallel=true
#Wed Sep 12 17:58:18 CST 2018
systemProp.https.proxyPort=1080
systemProp.http.proxyHost=127.0.0.1
org.gradle.jvmargs=-Xmx1536m
systemProp.https.proxyHost=127.0.0.1
systemProp.http.proxyPort=1080
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论