123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998 |
- #include <stdio.h>
- #include <sys/time.h>
- #include <sys/timeb.h>
- #include <unistd.h>
- typedef void(*VideoCallback)(unsigned char *buff, int size, double timestamp);
- typedef void(*AudioCallback)(unsigned char *buff, int size, double timestamp);
- typedef void(*RequestCallback)(int offset, int available);
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include "libavcodec/avcodec.h"
- #include "libavformat/avformat.h"
- #include "libavutil/fifo.h"
- //#include "libswscale/swscale.h"
- #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
- const int kCustomIoBufferSize = 32 * 1024;
- const int kInitialPcmBufferSize = 128 * 1024;
- const int kDefaultFifoSize = 1 * 1024 * 1024;
- const int kMaxFifoSize = 16 * 1024 * 1024;
- typedef enum ErrorCode {
- kErrorCode_Success = 0,
- kErrorCode_Invalid_Param,
- kErrorCode_Invalid_State,
- kErrorCode_Invalid_Data,
- kErrorCode_Invalid_Format,
- kErrorCode_NULL_Pointer,
- kErrorCode_Open_File_Error,
- kErrorCode_Eof,
- kErrorCode_FFmpeg_Error,
- kErrorCode_Old_Frame
- } ErrorCode;
- typedef enum LogLevel {
- kLogLevel_None, //Not logging.
- kLogLevel_Core, //Only logging core module(without ffmpeg).
- kLogLevel_All //Logging all, with ffmpeg.
- } LogLevel;
- typedef struct WebDecoder {
- AVFormatContext *avformatContext;
- AVCodecContext *videoCodecContext;
- AVCodecContext *audioCodecContext;
- AVFrame *avFrame;
- int videoStreamIdx;
- int audioStreamIdx;
- VideoCallback videoCallback;
- AudioCallback audioCallback;
- RequestCallback requestCallback;
- unsigned char *yuvBuffer;
- //unsigned char *rgbBuffer;
- unsigned char *pcmBuffer;
- int currentPcmBufferSize;
- int videoBufferSize;
- int videoSize;
- //struct SwsContext* swsCtx;
- unsigned char *customIoBuffer;
- FILE *fp;
- char fileName[64];
- int64_t fileSize;
- int64_t fileReadPos;
- int64_t fileWritePos;
- int64_t lastRequestOffset;
- double beginTimeOffset;
- int accurateSeek;
- // For streaming.
- int isStream;
- AVFifoBuffer *fifo;
- int fifoSize;
- } WebDecoder;
- WebDecoder *decoder = NULL;
- LogLevel logLevel = kLogLevel_None;
- int getAailableDataSize();
- unsigned long getTickCount() {
- struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return ts.tv_sec * (unsigned long)1000 + ts.tv_nsec / 1000000;
- }
- void simpleLog(const char* format, ...) {
- if (logLevel == kLogLevel_None) {
- return;
- }
- char szBuffer[1024] = { 0 };
- char szTime[32] = { 0 };
- char *p = NULL;
- int prefixLength = 0;
- const char *tag = "Core";
- struct tm tmTime;
- struct timeb tb;
- ftime(&tb);
- localtime_r(&tb.time, &tmTime);
- if (1) {
- int tmYear = tmTime.tm_year + 1900;
- int tmMon = tmTime.tm_mon + 1;
- int tmMday = tmTime.tm_mday;
- int tmHour = tmTime.tm_hour;
- int tmMin = tmTime.tm_min;
- int tmSec = tmTime.tm_sec;
- int tmMillisec = tb.millitm;
- sprintf(szTime, "%d-%d-%d %d:%d:%d.%d", tmYear, tmMon, tmMday, tmHour, tmMin, tmSec, tmMillisec);
- }
- 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);
- }
- 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;
- simpleLog("%s", line);
- }
- int openCodecContext(AVFormatContext *fmtCtx, enum AVMediaType type, int *streamIdx, AVCodecContext **decCtx) {
- int ret = 0;
- do {
- int streamIndex = -1;
- AVStream *st = NULL;
- AVCodec *dec = NULL;
- AVDictionary *opts = NULL;
- ret = av_find_best_stream(fmtCtx, type, -1, -1, NULL, 0);
- if (ret < 0) {
- simpleLog("Could not find %s stream.", av_get_media_type_string(type));
- break;
- }
- streamIndex = ret;
- st = fmtCtx->streams[streamIndex];
- dec = avcodec_find_decoder(st->codecpar->codec_id);
- if (!dec) {
- simpleLog("Failed to find %s codec %d.", av_get_media_type_string(type), st->codecpar->codec_id);
- ret = AVERROR(EINVAL);
- break;
- }
- *decCtx = avcodec_alloc_context3(dec);
- if (!*decCtx) {
- simpleLog("Failed to allocate the %s codec context.", av_get_media_type_string(type));
- ret = AVERROR(ENOMEM);
- break;
- }
- if ((ret = avcodec_parameters_to_context(*decCtx, st->codecpar)) != 0) {
- simpleLog("Failed to copy %s codec parameters to decoder context.", av_get_media_type_string(type));
- break;
- }
- av_dict_set(&opts, "refcounted_frames", "0", 0);
- if ((ret = avcodec_open2(*decCtx, dec, NULL)) != 0) {
- simpleLog("Failed to open %s codec.", av_get_media_type_string(type));
- break;
- }
- *streamIdx = streamIndex;
- avcodec_flush_buffers(*decCtx);
- } while (0);
- return ret;
- }
- void closeCodecContext(AVFormatContext *fmtCtx, AVCodecContext *decCtx, int streamIdx) {
- do {
- if (fmtCtx == NULL || decCtx == NULL) {
- break;
- }
- if (streamIdx < 0 || streamIdx >= fmtCtx->nb_streams) {
- break;
- }
- fmtCtx->streams[streamIdx]->discard = AVDISCARD_ALL;
- avcodec_close(decCtx);
- } while (0);
- }
- ErrorCode copyYuvData(AVFrame *frame, unsigned char *buffer, int width, int height) {
- ErrorCode ret = kErrorCode_Success;
- unsigned char *src = NULL;
- unsigned char *dst = buffer;
- int i = 0;
- do {
- if (frame == NULL || buffer == NULL) {
- ret = kErrorCode_Invalid_Param;
- break;
- }
- if (!frame->data[0] || !frame->data[1] || !frame->data[2]) {
- ret = kErrorCode_Invalid_Param;
- break;
- }
- for (i = 0; i < height; i++) {
- src = frame->data[0] + i * frame->linesize[0];
- memcpy(dst, src, width);
- dst += width;
- }
- for (i = 0; i < height / 2; i++) {
- src = frame->data[1] + i * frame->linesize[1];
- memcpy(dst, src, width / 2);
- dst += width / 2;
- }
- for (i = 0; i < height / 2; i++) {
- src = frame->data[2] + i * frame->linesize[2];
- memcpy(dst, src, width / 2);
- dst += width / 2;
- }
- } while (0);
- return ret;
- }
- /*
- ErrorCode yuv420pToRgb32(unsigned char *yuvBuff, unsigned char *rgbBuff, int width, int height) {
- ErrorCode ret = kErrorCode_Success;
- AVPicture yuvPicture, rgbPicture;
- uint8_t *ptmp = NULL;
- do {
- if (yuvBuff == NULL || rgbBuff == NULL) {
- ret = kErrorCode_Invalid_Param
- break;
- }
- if (decoder == NULL || decoder->swsCtx == NULL) {
- ret = kErrorCode_Invalid_Param
- break;
- }
-
- avpicture_fill(&yuvPicture, yuvBuff, AV_PIX_FMT_YUV420P, width, height);
- avpicture_fill(&rgbPicture, rgbBuff, AV_PIX_FMT_RGB32, width, height);
- ptmp = yuvPicture.data[1];
- yuvPicture.data[1] = yuvPicture.data[2];
- yuvPicture.data[2] = ptmp;
- sws_scale(decoder->swsCtx, yuvPicture.data, yuvPicture.linesize, 0, height, rgbPicture.data, rgbPicture.linesize);
- } while (0);
- return ret;
- }
- */
- int roundUp(int numToRound, int multiple) {
- return (numToRound + multiple - 1) & -multiple;
- }
- ErrorCode processDecodedVideoFrame(AVFrame *frame) {
- ErrorCode ret = kErrorCode_Success;
- double timestamp = 0.0f;
- do {
- if (frame == NULL ||
- decoder->videoCallback == NULL ||
- decoder->yuvBuffer == NULL ||
- decoder->videoBufferSize <= 0) {
- ret = kErrorCode_Invalid_Param;
- break;
- }
- if (decoder->videoCodecContext->pix_fmt != AV_PIX_FMT_YUV420P) {
- simpleLog("Not YUV420P, but unsupported format %d.", decoder->videoCodecContext->pix_fmt);
- ret = kErrorCode_Invalid_Format;
- break;
- }
- ret = copyYuvData(frame, decoder->yuvBuffer, decoder->videoCodecContext->width, decoder->videoCodecContext->height);
- if (ret != kErrorCode_Success) {
- break;
- }
- /*
- ret = yuv420pToRgb32(decoder->yuvBuffer, decoder->rgbBuffer, decoder->videoCodecContext->width, decoder->videoCodecContext->height);
- if (ret != kErrorCode_Success) {
- break;
- }
- */
- timestamp = (double)frame->pts * av_q2d(decoder->avformatContext->streams[decoder->videoStreamIdx]->time_base);
- if (decoder->accurateSeek && timestamp < decoder->beginTimeOffset) {
- //simpleLog("video timestamp %lf < %lf", timestamp, decoder->beginTimeOffset);
- ret = kErrorCode_Old_Frame;
- break;
- }
- decoder->videoCallback(decoder->yuvBuffer, decoder->videoSize, timestamp);
- } while (0);
- return ret;
- }
- ErrorCode processDecodedAudioFrame(AVFrame *frame) {
- ErrorCode ret = kErrorCode_Success;
- int sampleSize = 0;
- int audioDataSize = 0;
- int targetSize = 0;
- int offset = 0;
- int i = 0;
- int ch = 0;
- double timestamp = 0.0f;
- do {
- if (frame == NULL) {
- ret = kErrorCode_Invalid_Param;
- break;
- }
- sampleSize = av_get_bytes_per_sample(decoder->audioCodecContext->sample_fmt);
- if (sampleSize < 0) {
- simpleLog("Failed to calculate data size.");
- ret = kErrorCode_Invalid_Data;
- break;
- }
- if (decoder->pcmBuffer == NULL) {
- decoder->pcmBuffer = (unsigned char*)av_mallocz(kInitialPcmBufferSize);
- decoder->currentPcmBufferSize = kInitialPcmBufferSize;
- simpleLog("Initial PCM buffer size %d.", decoder->currentPcmBufferSize);
- }
- audioDataSize = frame->nb_samples * decoder->audioCodecContext->channels * sampleSize;
- if (decoder->currentPcmBufferSize < audioDataSize) {
- targetSize = roundUp(audioDataSize, 4);
- simpleLog("Current PCM buffer size %d not sufficient for data size %d, round up to target %d.",
- decoder->currentPcmBufferSize,
- audioDataSize,
- targetSize);
- decoder->currentPcmBufferSize = targetSize;
- av_free(decoder->pcmBuffer);
- decoder->pcmBuffer = (unsigned char*)av_mallocz(decoder->currentPcmBufferSize);
- }
- for (i = 0; i < frame->nb_samples; i++) {
- for (ch = 0; ch < decoder->audioCodecContext->channels; ch++) {
- memcpy(decoder->pcmBuffer + offset, frame->data[ch] + sampleSize * i, sampleSize);
- offset += sampleSize;
- }
- }
- timestamp = (double)frame->pts * av_q2d(decoder->avformatContext->streams[decoder->audioStreamIdx]->time_base);
- if (decoder->accurateSeek && timestamp < decoder->beginTimeOffset) {
- //simpleLog("audio timestamp %lf < %lf", timestamp, decoder->beginTimeOffset);
- ret = kErrorCode_Old_Frame;
- break;
- }
- if (decoder->audioCallback != NULL) {
- decoder->audioCallback(decoder->pcmBuffer, audioDataSize, timestamp);
- }
- } while (0);
- return ret;
- }
- ErrorCode decodePacket(AVPacket *pkt, int *decodedLen) {
- int ret = 0;
- int isVideo = 0;
- AVCodecContext *codecContext = NULL;
- if (pkt == NULL || decodedLen == NULL) {
- simpleLog("decodePacket invalid param.");
- return kErrorCode_Invalid_Param;
- }
- *decodedLen = 0;
- if (pkt->stream_index == decoder->videoStreamIdx) {
- codecContext = decoder->videoCodecContext;
- isVideo = 1;
- } else if (pkt->stream_index == decoder->audioStreamIdx) {
- codecContext = decoder->audioCodecContext;
- isVideo = 0;
- } else {
- return kErrorCode_Invalid_Data;
- }
- ret = avcodec_send_packet(codecContext, pkt);
- if (ret < 0) {
- simpleLog("Error sending a packet for decoding %d.", ret);
- return kErrorCode_FFmpeg_Error;
- }
- while (ret >= 0) {
- ret = avcodec_receive_frame(codecContext, decoder->avFrame);
- if (ret == AVERROR(EAGAIN)) {
- return kErrorCode_Success;
- } else if (ret == AVERROR_EOF) {
- return kErrorCode_Eof;
- } else if (ret < 0) {
- simpleLog("Error during decoding %d.", ret);
- return kErrorCode_FFmpeg_Error;
- } else {
- int r = isVideo ? processDecodedVideoFrame(decoder->avFrame) : processDecodedAudioFrame(decoder->avFrame);
- if (r == kErrorCode_Old_Frame) {
- return r;
- }
- }
- }
- *decodedLen = pkt->size;
- return kErrorCode_Success;
- }
- int readFromFile(uint8_t *data, int len) {
- //simpleLog("readFromFile %d.", len);
- int32_t ret = -1;
- int availableBytes = 0;
- int canReadLen = 0;
- do {
- if (decoder->fp == NULL) {
- break;
- }
- availableBytes = decoder->fileWritePos - decoder->fileReadPos;
- if (availableBytes <= 0) {
- break;
- }
- fseek(decoder->fp, decoder->fileReadPos, SEEK_SET);
- canReadLen = MIN(availableBytes, len);
- fread(data, canReadLen, 1, decoder->fp);
- decoder->fileReadPos += canReadLen;
- ret = canReadLen;
- } while (0);
- //simpleLog("readFromFile ret %d.", ret);
- return ret;
- }
- int readFromFifo(uint8_t *data, int len) {
- //simpleLog("readFromFifo %d.", len);
- int32_t ret = -1;
- int availableBytes = 0;
- int canReadLen = 0;
- do {
- if (decoder->fifo == NULL) {
- break;
- }
- availableBytes = av_fifo_size(decoder->fifo);
- if (availableBytes <= 0) {
- break;
- }
- canReadLen = MIN(availableBytes, len);
- av_fifo_generic_read(decoder->fifo, data, canReadLen, NULL);
- ret = canReadLen;
- } while (0);
- //simpleLog("readFromFifo ret %d, left %d.", ret, av_fifo_size(decoder->fifo));
- return ret;
- }
- int readCallback(void *opaque, uint8_t *data, int len) {
- //simpleLog("readCallback %d.", len);
- int32_t ret = -1;
- do {
- if (decoder == NULL) {
- break;
- }
- if (data == NULL || len <= 0) {
- break;
- }
- ret = decoder->isStream ? readFromFifo(data, len) : readFromFile(data, len);
- } while (0);
- //simpleLog("readCallback ret %d.", ret);
- return ret;
- }
- int64_t seekCallback(void *opaque, int64_t offset, int whence) {
- int64_t ret = -1;
- int64_t pos = -1;
- int64_t req_pos = -1;
- //simpleLog("seekCallback %lld %d.", offset, whence);
- do {
- if (decoder == NULL || decoder->isStream || decoder->fp == NULL) {
- break;
- }
- if (whence == AVSEEK_SIZE) {
- ret = decoder->fileSize;
- break;
- }
- if (whence != SEEK_END && whence != SEEK_SET && whence != SEEK_CUR) {
- break;
- }
- ret = fseek(decoder->fp, (long)offset, whence);
- if (ret == -1) {
- break;
- }
- pos = (int64_t)ftell(decoder->fp);
- if (pos < decoder->lastRequestOffset || pos > decoder->fileWritePos) {
- decoder->lastRequestOffset = pos;
- decoder->fileReadPos = pos;
- decoder->fileWritePos = pos;
- req_pos = pos;
- ret = -1; // Forcing not to call read at once.
- decoder->requestCallback(pos, getAailableDataSize());
- simpleLog("Will request %lld and return %lld.", pos, ret);
- break;
- }
- decoder->fileReadPos = pos;
- ret = pos;
- } while (0);
- //simpleLog("seekCallback return %lld.", ret);
- if (decoder != NULL && decoder->requestCallback != NULL) {
- decoder->requestCallback(req_pos, getAailableDataSize());
- }
- return ret;
- }
- int writeToFile(unsigned char *buff, int size) {
- int ret = 0;
- int64_t leftBytes = 0;
- int canWriteBytes = 0;
- do {
- if (decoder->fp == NULL) {
- ret = -1;
- break;
- }
- leftBytes = decoder->fileSize - decoder->fileWritePos;
- if (leftBytes <= 0) {
- break;
- }
- canWriteBytes = MIN(leftBytes, size);
- fseek(decoder->fp, decoder->fileWritePos, SEEK_SET);
- fwrite(buff, canWriteBytes, 1, decoder->fp);
- decoder->fileWritePos += canWriteBytes;
- ret = canWriteBytes;
- } while (0);
- return ret;
- }
- int writeToFifo(unsigned char *buff, int size) {
- int ret = 0;
- do {
- if (decoder->fifo == NULL) {
- ret = -1;
- break;
- }
- int64_t leftSpace = av_fifo_space(decoder->fifo);
- if (leftSpace < size) {
- int growSize = 0;
- do {
- leftSpace += decoder->fifoSize;
- growSize += decoder->fifoSize;
- decoder->fifoSize += decoder->fifoSize;
- } while (leftSpace < size);
- av_fifo_grow(decoder->fifo, growSize);
- simpleLog("Fifo size growed to %d.", decoder->fifoSize);
- if (decoder->fifoSize >= kMaxFifoSize) {
- simpleLog("[Warn] Fifo size larger than %d.", kMaxFifoSize);
- }
- }
- //simpleLog("Wrote %d bytes to fifo, total %d.", size, av_fifo_size(decoder->fifo));
- ret = av_fifo_generic_write(decoder->fifo, buff, size, NULL);
- } while (0);
- return ret;
- }
- int getAailableDataSize() {
- int ret = 0;
- do {
- if (decoder == NULL) {
- break;
- }
- if (decoder->isStream) {
- ret = decoder->fifo == NULL ? 0 : av_fifo_size(decoder->fifo);
- } else {
- ret = decoder->fileWritePos - decoder->fileReadPos;
- }
- } while (0);
- return ret;
- }
- //////////////////////////////////Export methods////////////////////////////////////////
- ErrorCode initDecoder(int fileSize, int logLv) {
- ErrorCode ret = kErrorCode_Success;
- do {
- //Log level.
- logLevel = logLv;
- if (decoder != NULL) {
- break;
- }
- decoder = (WebDecoder *)av_mallocz(sizeof(WebDecoder));
- if (fileSize >= 0) {
- decoder->fileSize = fileSize;
- sprintf(decoder->fileName, "tmp-%lu.mp4", getTickCount());
- decoder->fp = fopen(decoder->fileName, "wb+");
- if (decoder->fp == NULL) {
- simpleLog("Open file %s failed, err: %d.", decoder->fileName, errno);
- ret = kErrorCode_Open_File_Error;
- av_free(decoder);
- decoder = NULL;
- }
- } else {
- decoder->isStream = 1;
- decoder->fifoSize = kDefaultFifoSize;
- decoder->fifo = av_fifo_alloc(decoder->fifoSize);
- }
- } while (0);
- simpleLog("Decoder initialized %d.", ret);
- return ret;
- }
- ErrorCode uninitDecoder() {
- if (decoder != NULL) {
- if (decoder->fp != NULL) {
- fclose(decoder->fp);
- decoder->fp = NULL;
- remove(decoder->fileName);
- }
- if (decoder->fifo != NULL) {
- av_fifo_freep(&decoder->fifo);
- }
- av_freep(&decoder);
- }
- av_log_set_callback(NULL);
- simpleLog("Decoder uninitialized.");
- return kErrorCode_Success;
- }
- ErrorCode openDecoder(int *paramArray, int paramCount, long videoCallback, long audioCallback, long requestCallback) {
- ErrorCode ret = kErrorCode_Success;
- int r = 0;
- int i = 0;
- int params[7] = { 0 };
- do {
- simpleLog("打开编码器.");
- av_register_all();
- avcodec_register_all();
- if (logLevel == kLogLevel_All) {
- av_log_set_callback(ffmpegLogCallback);
- }
-
- decoder->avformatContext = avformat_alloc_context();
- decoder->customIoBuffer = (unsigned char*)av_mallocz(kCustomIoBufferSize);
- AVIOContext* ioContext = avio_alloc_context(
- decoder->customIoBuffer,
- kCustomIoBufferSize,
- 0,
- NULL,
- readCallback,
- NULL,
- seekCallback);
- if (ioContext == NULL) {
- ret = kErrorCode_FFmpeg_Error;
- simpleLog("avio_alloc_context failed.");
- break;
- }
- decoder->avformatContext->pb = ioContext;
- decoder->avformatContext->flags = AVFMT_FLAG_CUSTOM_IO;
- simpleLog("avformat_open_input.");
- r = avformat_open_input(&decoder->avformatContext, NULL, NULL, NULL);
- if (r != 0) {
- ret = kErrorCode_FFmpeg_Error;
- char err_info[32] = { 0 };
- av_strerror(ret, err_info, 32);
- simpleLog("avformat_open_input failed %d %s.", ret, err_info);
- break;
- }
-
- simpleLog("avformat_find_stream_info");
- r = avformat_find_stream_info(decoder->avformatContext, NULL);
- if (r != 0) {
- ret = kErrorCode_FFmpeg_Error;
- simpleLog("av_find_stream_info failed %d.", ret);
- break;
- }
-
-
-
- simpleLog("avformat_find_stream_info 成功.");
- for (i = 0; i < decoder->avformatContext->nb_streams; i++) {
- decoder->avformatContext->streams[i]->discard = AVDISCARD_DEFAULT;
- }
- r = openCodecContext(
- decoder->avformatContext,
- AVMEDIA_TYPE_VIDEO,
- &decoder->videoStreamIdx,
- &decoder->videoCodecContext);
- if (r != 0) {
- ret = kErrorCode_FFmpeg_Error;
- simpleLog("Open video codec context failed %d.", ret);
- break;
- }
- simpleLog("Open video codec context success, video stream index %d %x.",
- decoder->videoStreamIdx, (unsigned int)decoder->videoCodecContext);
- simpleLog("Video stream index:%d pix_fmt:%d resolution:%d*%d.",
- decoder->videoStreamIdx,
- decoder->videoCodecContext->pix_fmt,
- decoder->videoCodecContext->width,
- decoder->videoCodecContext->height);
- r = openCodecContext(
- decoder->avformatContext,
- AVMEDIA_TYPE_AUDIO,
- &decoder->audioStreamIdx,
- &decoder->audioCodecContext);
- if (r != 0) {
- ret = kErrorCode_FFmpeg_Error;
- simpleLog("Open audio codec context failed %d.", ret);
- break;
- }
- simpleLog("Open audio codec context success, audio stream index %d %x.",
- decoder->audioStreamIdx, (unsigned int)decoder->audioCodecContext);
- simpleLog("Audio stream index:%d sample_fmt:%d channel:%d, sample rate:%d.",
- decoder->audioStreamIdx,
- decoder->audioCodecContext->sample_fmt,
- decoder->audioCodecContext->channels,
- decoder->audioCodecContext->sample_rate);
- av_seek_frame(decoder->avformatContext, -1, 0, AVSEEK_FLAG_BACKWARD);
- /* For RGB Renderer(2D WebGL).
- decoder->swsCtx = sws_getContext(
- decoder->videoCodecContext->width,
- decoder->videoCodecContext->height,
- decoder->videoCodecContext->pix_fmt,
- decoder->videoCodecContext->width,
- decoder->videoCodecContext->height,
- AV_PIX_FMT_RGB32,
- SWS_BILINEAR,
- 0,
- 0,
- 0);
- if (decoder->swsCtx == NULL) {
- simpleLog("sws_getContext failed.");
- ret = kErrorCode_FFmpeg_Error;
- break;
- }
- */
-
- decoder->videoSize = avpicture_get_size(
- decoder->videoCodecContext->pix_fmt,
- decoder->videoCodecContext->width,
- decoder->videoCodecContext->height);
- decoder->videoBufferSize = 3 * decoder->videoSize;
- decoder->yuvBuffer = (unsigned char *)av_mallocz(decoder->videoBufferSize);
- decoder->avFrame = av_frame_alloc();
-
- params[0] = 1000 * (decoder->avformatContext->duration + 5000) / AV_TIME_BASE;
- params[1] = decoder->videoCodecContext->pix_fmt;
- params[2] = decoder->videoCodecContext->width;
- params[3] = decoder->videoCodecContext->height;
- params[4] = decoder->audioCodecContext->sample_fmt;
- params[5] = decoder->audioCodecContext->channels;
- params[6] = decoder->audioCodecContext->sample_rate;
- enum AVSampleFormat sampleFmt = decoder->audioCodecContext->sample_fmt;
- if (av_sample_fmt_is_planar(sampleFmt)) {
- const char *packed = av_get_sample_fmt_name(sampleFmt);
- params[4] = av_get_packed_sample_fmt(sampleFmt);
- }
- if (paramArray != NULL && paramCount > 0) {
- for (int i = 0; i < paramCount; ++i) {
- paramArray[i] = params[i];
- }
- }
- decoder->videoCallback = (VideoCallback)videoCallback;
- decoder->audioCallback = (AudioCallback)audioCallback;
- decoder->requestCallback = (RequestCallback)requestCallback;
- simpleLog("Decoder opened, duration %ds, picture size %d.", params[0], decoder->videoSize);
- } while (0);
- if (ret != kErrorCode_Success && decoder != NULL) {
- av_freep(&decoder);
- }
- return ret;
- }
- ErrorCode closeDecoder() {
- ErrorCode ret = kErrorCode_Success;
- do {
- if (decoder == NULL || decoder->avformatContext == NULL) {
- break;
- }
- if (decoder->videoCodecContext != NULL) {
- closeCodecContext(decoder->avformatContext, decoder->videoCodecContext, decoder->videoStreamIdx);
- decoder->videoCodecContext = NULL;
- simpleLog("Video codec context closed.");
- }
- if (decoder->audioCodecContext != NULL) {
- closeCodecContext(decoder->avformatContext, decoder->audioCodecContext, decoder->audioStreamIdx);
- decoder->audioCodecContext = NULL;
- simpleLog("Audio codec context closed.");
- }
- AVIOContext *pb = decoder->avformatContext->pb;
- if (pb != NULL) {
- if (pb->buffer != NULL) {
- av_freep(&pb->buffer);
- decoder->customIoBuffer = NULL;
- }
- av_freep(&decoder->avformatContext->pb);
- simpleLog("IO context released.");
- }
- avformat_close_input(&decoder->avformatContext);
- decoder->avformatContext = NULL;
- simpleLog("Input closed.");
- if (decoder->yuvBuffer != NULL) {
- av_freep(&decoder->yuvBuffer);
- }
- if (decoder->pcmBuffer != NULL) {
- av_freep(&decoder->pcmBuffer);
- }
-
- if (decoder->avFrame != NULL) {
- av_freep(&decoder->avFrame);
- }
- simpleLog("All buffer released.");
- } while (0);
- return ret;
- }
- int sendData(unsigned char *buff, int size) {
- int ret = 0;
- int64_t leftBytes = 0;
- int canWriteBytes = 0;
- do {
- if (decoder == NULL) {
- ret = -1;
- break;
- }
- if (buff == NULL || size == 0) {
- ret = -2;
- break;
- }
- ret = decoder->isStream ? writeToFifo(buff, size) : writeToFile(buff, size);
- } while (0);
- return ret;
- }
- ErrorCode decodeOnePacket() {
- ErrorCode ret = kErrorCode_Success;
- int decodedLen = 0;
- int r = 0;
- AVPacket packet;
- av_init_packet(&packet);
- do {
- if (decoder == NULL) {
- ret = kErrorCode_Invalid_State;
- break;
- }
- if (getAailableDataSize() <= 0) {
- ret = kErrorCode_Invalid_State;
- break;
- }
- packet.data = NULL;
- packet.size = 0;
- r = av_read_frame(decoder->avformatContext, &packet);
- if (r == AVERROR_EOF) {
- ret = kErrorCode_Eof;
- break;
- }
- if (r < 0 || packet.size == 0) {
- break;
- }
- do {
- ret = decodePacket(&packet, &decodedLen);
- if (ret != kErrorCode_Success) {
- break;
- }
- if (decodedLen <= 0) {
- break;
- }
- packet.data += decodedLen;
- packet.size -= decodedLen;
- } while (packet.size > 0);
- } while (0);
- av_packet_unref(&packet);
- return ret;
- }
- ErrorCode seekTo(int ms, int accurateSeek) {
- int ret = 0;
- int64_t pts = (int64_t)ms * 1000;
- decoder->accurateSeek = accurateSeek;
- ret = avformat_seek_file(decoder->avformatContext,
- -1,
- INT64_MIN,
- pts,
- pts,
- AVSEEK_FLAG_BACKWARD);
- simpleLog("Native seek to %d return %d %d.", ms, ret, decoder->accurateSeek);
- if (ret == -1) {
- return kErrorCode_FFmpeg_Error;
- } else {
- avcodec_flush_buffers(decoder->videoCodecContext);
- avcodec_flush_buffers(decoder->audioCodecContext);
- // Trigger seek callback
- AVPacket packet;
- av_init_packet(&packet);
- av_read_frame(decoder->avformatContext, &packet);
- decoder->beginTimeOffset = (double)ms / 1000;
- return kErrorCode_Success;
- }
- }
- int main() {
- //simpleLog("Native loaded.");
- return 0;
- }
- #ifdef __cplusplus
- }
- #endif
|