// // Created by 阳坤 on 2022/1/12. // #ifndef JNI_WEB_TOOLS_H #define JNI_WEB_TOOLS_H #define LOGE(format, ...) Log(format,##__VA_ARGS__); #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) #define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stdio.h" #define kCustomIoBufferSize 32 * 1024 #define kInitialPcmBufferSize 128 * 1024 #define kDefaultFifoSize 1 * 1024 * 1024 #define kMaxFifoSize 16 * 1024 * 1024 #define DEFAULT_AUDIO_SAMPLE_RATE 44100 #define DEFAULT_AUDIO_CHANNELS 2 #define DEFAULT_VIDEO_FPS 25 #define DEFAULT_FORCE_PRECISION 0 static FILE *pFile = NULL; static inline void print_ffmpeg_suport_codec() { AVCodec *codec = av_codec_next(NULL); char *info = (char *) malloc(40000); memset(info, 0, 40000); while (codec != NULL) { if (codec->decode != NULL) { strcat(info, "[Decode]"); } else { strcat(info, "[Encode]"); } switch (codec->type) { case AVMEDIA_TYPE_VIDEO: strcat(info, "[Video]"); break; case AVMEDIA_TYPE_AUDIO: strcat(info, "[Audeo]"); break; default: strcat(info, "[Other]"); break; } sprintf(info, "%s %10s\n", info, codec->name); codec = codec->next; } puts(info); free(info); } static inline void split(char *str_, char delims[], long ret[], int *count) { int len = strlen(str_); char str[strlen(str_) + 1]; for (int i = 0; i < len; i++) { str[i] = str_[i]; } str[len] = '\0'; char *result = NULL; result = strtok(str, delims); int index = 0; while (result != NULL) { ret[index++] = atol(result); result = strtok(NULL, delims); } *count = index; } static inline long getCurrentTimeMills() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000 + tv.tv_usec / 1000; } static inline void Log(const char *format, ...) { char szBuffer[1024] = {0}; char szTime[1024] = {0}; char *p = NULL; int prefixLength = 0; const char *tag = "Core"; time_t t; //秒时间 struct tm *local; //本地时间 t = time(NULL); //获取目前秒时间 local = localtime(&t); //转为本地时间,注意,该函数非线程安全,下面的例子会使用线程安全函数localtime_r if (1) { strftime(szTime, 64, "%Y-%m-%d %H:%M:%S", local); //根据需要自定义格式 } prefixLength = sprintf(szBuffer, "[%s][%s][DT] ", szTime, tag); p = szBuffer + prefixLength; if (1) { va_list ap; va_start(ap, format); vsnprintf(p, 1024 - prefixLength, format, ap); va_end(ap); } printf("%s\n", szBuffer); } static int getVideoRotate(AVDictionary *metadata); static int drop_or_add_frame_countV2(int cur_fps, int fix_fps, double sync_ipts, double sync_opts, int64_t next_pkt_duration, AVRational st_time_base); static int drop_or_add_frame_countV2(int cur_fps, int fix_fps, double sync_ipts, double sync_opts, int64_t next_pkt_duration, AVRational st_time_base) { int nb_frames; double delta, delta0; double duration = 1.0 / ((cur_fps / 1.0) * (1.0 / fix_fps)); duration = FFMIN(duration, 1.0 / ((fix_fps / 1.0) * (1.0 / fix_fps))); duration = lrintf(next_pkt_duration * av_q2d(st_time_base) / (1.0 / fix_fps)); delta0 = sync_ipts - sync_opts; delta = delta0 + duration; // LOGE("sync_ipts=%f sync_opts=%f delta=%f drop_frame=%d duration=%f \n", sync_ipts, sync_opts, delta, // delta < -1.1, duration); nb_frames = 1; //��ʱ����� ffmpeg.c Դ��Ҫ����Щ��û���õ���! if (delta0 < 0 && delta > 0 ) { // if (delta0 < -0.6) { // LOGE("Past duration %f too large\n", -delta0); // } else // LOGE("Clipping frame in rate conversion by %f\n", -delta0); sync_ipts = sync_opts; duration += delta0; delta0 = 0; } if (delta < -1.1) nb_frames = 0; else if (delta > 1.1) { nb_frames = lrintf(delta); } return nb_frames; } static int getVideoRotate(AVDictionary *metadata) { AVDictionaryEntry *tag = NULL; int m_Rotate = 0; tag = av_dict_get(metadata, "rotate", tag, m_Rotate); if (tag == NULL) { m_Rotate = 0; } else { int angle = atoi(tag->value); angle %= 360; if (angle == 90) { m_Rotate = 90; } else if (angle == 180) { m_Rotate = 180; } else if (angle == 270) { m_Rotate = 270; } else { m_Rotate = 0; } } return m_Rotate; } static void ffmpegLogCallback(void *ptr, int level, const char *fmt, va_list vl) { static int printPrefix = 1; static int count = 0; static char prev[1024] = {0}; char line[1024] = {0}; static int is_atty; AVClass *avc = ptr ? *(AVClass **) ptr : NULL; if (level > AV_LOG_DEBUG) { return; } line[0] = 0; if (printPrefix && avc) { if (avc->parent_log_context_offset) { AVClass **parent = *(AVClass ***) (((uint8_t *) ptr) + avc->parent_log_context_offset); if (parent && *parent) { snprintf(line, sizeof(line), "[%s @ %p] ", (*parent)->item_name(parent), parent); } } snprintf(line + strlen(line), sizeof(line) - strlen(line), "[%s @ %p] ", avc->item_name(ptr), ptr); } vsnprintf(line + strlen(line), sizeof(line) - strlen(line), fmt, vl); line[strlen(line) + 1] = 0; LOGE("%s", line); } static int GetAACSampleRateIndex(int sampling_frequency) { switch (sampling_frequency) { case 96000: return 0; case 88200: return 1; case 64000: return 2; case 48000: return 3; case 44100: return 4; case 32000: return 5; case 24000: return 6; case 22050: return 7; case 16000: return 8; case 12000: return 9; case 11025: return 10; case 8000: return 11; case 7350: return 12; default: return 0; } } static void close_file() { if (pFile) { fclose(pFile); pFile = NULL; } } static void savaFrame(uint8_t *pFrame, int width, int height, int frame, int size, int isRgb) { char szFilename[1024]; //生成文件名称 sprintf(szFilename, "/Users/devyk/Data/Project/piaoquan/PQMedia/temp/image/frame%d.yuv", frame); //创建或打开文件 if (!pFile) pFile = fopen(szFilename, "wb"); if (pFile == NULL) { return; } if (isRgb) //写入头信息 fprintf(pFile, "P6\n%d %d\n225\n", width, height); //写入数据 fwrite(pFrame, 1, size, pFile); } //创建默认的帧 static int bf_create_default_frame(enum AVMediaType type, AVCodecContext *ctx, AVFrame **frame) { if (frame) { *frame = av_frame_alloc(); if (!(*frame = av_frame_alloc())) { LOGE("Could not allocate output frame\n"); return -1; } if (type == AVMEDIA_TYPE_AUDIO){ (*frame)->format = AV_SAMPLE_FMT_FLTP; (*frame)->channel_layout = AV_CH_LAYOUT_STEREO; (*frame)->sample_rate = DEFAULT_AUDIO_SAMPLE_RATE; (*frame)->channels = av_get_channel_layout_nb_channels((*frame)->channel_layout); (*frame)->nb_samples = 1024; if ((av_frame_get_buffer((*frame), 1)) != 0) { LOGE("av_frame_get_buffer fatal��\n"); av_frame_free(&(*frame)); (*frame) = NULL; return -1; } av_samples_set_silence((*frame)->data, 0, (*frame)->nb_samples, (*frame)->channels, (enum AVSampleFormat) (*frame)->format); (*frame)->pts = (*frame)->nb_samples; (*frame)->pkt_pts = (*frame)->nb_samples; (*frame)->pkt_dts = (*frame)->nb_samples; (*frame)->pkt_duration = (*frame)->nb_samples; } else if (type == AVMEDIA_TYPE_VIDEO){ (*frame)->format = AV_PIX_FMT_YUV420P; (*frame)->width = ctx->width; (*frame)->height = ctx->height; int ret = av_frame_get_buffer(*frame, 1); if (ret < 0) { LOGE("Could not allocate the video frame data\n"); return -1; } /* 生成黑色背景 */ /* Y */ for (int y = 0; y < (*frame)->height; y++) { for (int x = 0; x < (*frame)->width; x++) { (*frame)->data[0][y * (*frame)->linesize[0] + x] = 0; } } /* Cb and Cr */ for (int y = 0; y < (*frame)->height / 2; y++) { for (int x = 0; x < (*frame)->width / 2; x++) { (*frame)->data[1][y * (*frame)->linesize[1] + x] = 0x80; (*frame)->data[2][y * (*frame)->linesize[2] + x] = 0x80; } } } } return 0; } static int bf_frame_2_uint8_ptr(enum AVMediaType type,AVFrame *in,uint8_t**out_data,int format){ int sampleSize = 0; int audioDataSize = 0; int offset = 0; int i = 0; int ch = 0; enum AVSampleFormat sampleFormat = (enum AVSampleFormat)format; sampleSize = av_get_bytes_per_sample(sampleFormat); if (sampleSize < 0) { LOGE("Failed to calculate data size."); return -1; } audioDataSize = in->nb_samples * in->channels * sampleSize; int size = av_samples_get_buffer_size(NULL, av_get_channel_layout_nb_channels(AV_CH_LAYOUT_STEREO), in->nb_samples, sampleFormat, 0); *out_data = (uint8_t *) av_mallocz(audioDataSize); if (!(*out_data))return -1; if (av_sample_fmt_is_planar(sampleFormat)) {//如果是平面的 for (i = 0; i < in->nb_samples; i++) { for (ch = 0; ch < in->channels; ch++) { memcpy((*out_data) + offset, in->data[ch] + sampleSize * i, sampleSize); offset += sampleSize; } } } else { memcpy(*out_data, in->data[0], audioDataSize); } return audioDataSize; } #endif //JNI_WEB_TOOLS_H