FFmpeg中的日志以及avio实现对文件的读写功能
生活随笔
收集整理的這篇文章主要介紹了
FFmpeg中的日志以及avio实现对文件的读写功能
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
ffmpeg日志
ffmpeg日志,接口都定義在log.h,使用的庫是libavutil
使用時一定要加上對頭文件extern "C"外部,否則會報對應的函數沒有定義
// // Created by andrew on 2020/10/31. // #include <iostream> extern "C"{ #include <libavutil/log.h> }using namespace std;int main(int argc, char *argv[]) {av_log_set_level(AV_LOG_DEBUG);av_log(NULL, AV_LOG_DEBUG,"Hello world!\n");return 0; }執行結果:
Hello world!write file
第一步先設置日志等級,這里追溯下日志等級設置的實現。
av_log_set_level設置日志等級
前期追溯過的函數后面將不會進行重復追蹤定位。
av_log_set_level(AV_LOG_DEBUG);函數點擊進入函數,函數實現如下,只是設置了一個全局變量,用于記錄日志的等級
void av_log_set_level(int level) {av_log_level = level; }再看下實際使用時,函數是如何判定日志是否需要輸出的
void av_log(void* avcl, int level, const char *fmt, ...) {va_list vl;va_start(vl, fmt);av_vlog(avcl, level, fmt, vl);va_end(vl); } //實際調用 void av_vlog(void* avcl, int level, const char *fmt, va_list vl) {AVClass* avc = avcl ? *(AVClass **) avcl : NULL;void (*log_callback)(void*, int, const char*, va_list) = av_log_callback;if (avc && avc->version >= (50 << 16 | 15 << 8 | 2) &&avc->log_level_offset_offset && level >= AV_LOG_FATAL)level += *(int *) (((uint8_t *) avcl) + avc->log_level_offset_offset);if (log_callback)log_callback(avcl, level, fmt, vl); } // 回調函數指針 static void (*av_log_callback)(void*, int, const char*, va_list) =av_log_default_callback;//回調函數 void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) {static int print_prefix = 1;static int count;static char prev[LINE_SZ];AVBPrint part[4];char line[LINE_SZ];static int is_atty;int type[2];unsigned tint = 0;if (level >= 0) {tint = level & 0xff00;level &= 0xff;}// 這里是是否輸出日志的關鍵,只有level小于這個等級的時候才會輸出日志if (level > av_log_level)return;ff_mutex_lock(&mutex);format_line(ptr, level, fmt, vl, part, &print_prefix, type);snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str);#if HAVE_ISATTYif (!is_atty)is_atty = isatty(2) ? 1 : -1; #endifif (print_prefix && (flags & AV_LOG_SKIP_REPEATED) && !strcmp(line, prev) &&*line && line[strlen(line) - 1] != '\r'){count++;if (is_atty == 1)fprintf(stderr, " Last message repeated %d times\r", count);goto end;}if (count > 0) {fprintf(stderr, " Last message repeated %d times\n", count);count = 0;}strcpy(prev, line);sanitize(part[0].str);colored_fputs(type[0], 0, part[0].str);sanitize(part[1].str);colored_fputs(type[1], 0, part[1].str);sanitize(part[2].str);colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[2].str);sanitize(part[3].str);colored_fputs(av_clip(level >> 3, 0, NB_LEVELS - 1), tint >> 8, part[3].str);#if CONFIG_VALGRIND_BACKTRACEif (level <= BACKTRACE_LOGLEVEL)VALGRIND_PRINTF_BACKTRACE("%s", ""); #endif end:av_bprint_finalize(part+3, NULL);ff_mutex_unlock(&mutex); }實際日志等級的定義
/*** Print no output.*/ #define AV_LOG_QUIET -8/*** Something went really wrong and we will crash now.*/ #define AV_LOG_PANIC 0/*** Something went wrong and recovery is not possible.* For example, no header was found for a format which depends* on headers or an illegal combination of parameters is used.*/ #define AV_LOG_FATAL 8/*** Something went wrong and cannot losslessly be recovered.* However, not all future data is affected.*/ #define AV_LOG_ERROR 16/*** Something somehow does not look correct. This may or may not* lead to problems. An example would be the use of '-vstrict -2'.*/ #define AV_LOG_WARNING 24/*** Standard information.*/ #define AV_LOG_INFO 32/*** Detailed information.*/ #define AV_LOG_VERBOSE 40/*** Stuff which is only useful for libav* developers.*/ #define AV_LOG_DEBUG 48/*** Extremely verbose debugging, useful for libav* development.*/ #define AV_LOG_TRACE 56一般設置的時候我們會將日志打印等級設置為AV_LOG_DEBUG,這個等級非常大很少有大于這個等級的日志宏定義,因此在實際中設置這個等級大多數打印都會打印出來。
取出要寫的文件名字
char *pSrcFileName = argv[1];構建AVIOContext結構體
使用avio_open函數構建AVIOContext結構體
看下avio_open函數的調用關系
1. avio_open 函數調用了 avio_open2 /*** Create and initialize a AVIOContext for accessing the* resource indicated by url.* @note When the resource indicated by url has been opened in* read+write mode, the AVIOContext can be used only for writing.** @param s Used to return the pointer to the created AVIOContext.* In case of failure the pointed to value is set to NULL.* @param url resource to access* @param flags flags which control how the resource indicated by url* is to be opened* @return >= 0 in case of success, a negative value corresponding to an* AVERROR code in case of failure*/ int avio_open(AVIOContext **s, const char *url, int flags);2. avio_open函數調用了ffio_open_whitelist 3. ffio_open_whitelist函數調用了ffurl_open_whitelist 和ffio_fdopen 4. ffio_fdopen函數調用了 avio_alloc_context /*** Allocate and initialize an AVIOContext for buffered I/O. It must be later* freed with avio_context_free().** @param buffer Memory block for input/output operations via AVIOContext.* The buffer must be allocated with av_malloc() and friends.* It may be freed and replaced with a new buffer by libavformat.* AVIOContext.buffer holds the buffer currently in use,* which must be later freed with av_free().* @param buffer_size The buffer size is very important for performance.* For protocols with fixed blocksize it should be set to this blocksize.* For others a typical size is a cache page, e.g. 4kb.* @param write_flag Set to 1 if the buffer should be writable, 0 otherwise.* @param opaque An opaque pointer to user-specific data.* @param read_packet A function for refilling the buffer, may be NULL.* For stream protocols, must never return 0 but rather* a proper AVERROR code.* @param write_packet A function for writing the buffer contents, may be NULL.* The function may not change the input buffers content.* @param seek A function for seeking to specified byte position, may be NULL.** @return Allocated AVIOContext or NULL on failure.*/ AVIOContext *avio_alloc_context(unsigned char *buffer,int buffer_size,int write_flag,void *opaque,int (*read_packet)(void *opaque, uint8_t *buf, int buf_size),int (*write_packet)(void *opaque, uint8_t *buf, int buf_size),int64_t (*seek)(void *opaque, int64_t offset, int whence));將數據寫入文件
avio_write將傳入的buff寫入到AVIOContext關聯的結構體中
void avio_write(AVIOContext *s, const unsigned char *buf, int size) {if (s->direct && !s->update_checksum) {avio_flush(s);writeout(s, buf, size);return;}// 循環將傳入的buf 字符串寫入到s中的buf緩沖區中while (size > 0) {int len = FFMIN(s->buf_end - s->buf_ptr, size);memcpy(s->buf_ptr, buf, len);s->buf_ptr += len;if (s->buf_ptr >= s->buf_end)flush_buffer(s);buf += len;size -= len;} }釋放申請的資源
使用avio_close釋放申請的資源
代碼實現如下
// // Created by andrew on 2020/11/7. //#include <iostream>extern "C" { #include <libavutil/log.h> #include <libavformat/avio.h> }using namespace std;int main(int argc, char *argv[]) {// 設置日志等級av_log_set_level(AV_LOG_DEBUG);if (argc < 2) {av_log(NULL, AV_LOG_ERROR, "The count of parameter should be more than two!\n");exit(1);}char *pSrcFileName = argv[1];if (NULL == pSrcFileName) {av_log(NULL, AV_LOG_ERROR, "invalid src filename.\n");exit(2);}AVIOContext *avioCtx = NULL;int errCode = -1;/** Create and initialize a AVIOContext for accessing the* resource indicated by url.* */if ((errCode = avio_open(&avioCtx, pSrcFileName, AVIO_FLAG_WRITE)) < 0) {av_log(NULL, AV_LOG_ERROR, "Coud not open file %s\n", pSrcFileName);exit(3);}string strBuff = "hello world!\n";avio_write(avioCtx, (const unsigned char *)(strBuff.c_str()), strBuff.length());avio_close(avioCtx);char tempBuff[128];snprintf(tempBuff, sizeof(tempBuff), "cat %s", pSrcFileName);system(tempBuff);snprintf(tempBuff, sizeof(tempBuff), "rm %s", pSrcFileName);system(tempBuff);return 0; } #運行結果,編譯時連接上對應的庫文件 ./ffmpeg_io_write test.txt hello world! #運行結果,編譯時連接上對應的庫文件 ./ffmpeg_io_write test.txt hello world!read file
讀文件和寫文件實現基本上一樣,需要改動的點是,打開文件時,將標志設置為AVIO_FLAG_READ并將avio_write修改為avio_read函數。
代碼實現如下:
// // Created by andrew on 2020/11/8. //// // Created by andrew on 2020/11/7. //#include <iostream>extern "C" { #include <libavutil/log.h> #include <libavformat/avio.h> }using namespace std;int main(int argc, char *argv[]) {char tempBuff[128];// 設置日志等級av_log_set_level(AV_LOG_DEBUG);if (argc < 2) {av_log(NULL, AV_LOG_ERROR, "The count of parameter should be more than two!\n");exit(1);}char *pSrcFileName = argv[1];if (NULL == pSrcFileName) {av_log(NULL, AV_LOG_ERROR, "invalid src filename.\n");exit(2);}// 創建一個文件snprintf(tempBuff, sizeof(tempBuff), "echo \"hello world!\n \" > %s", pSrcFileName);system(tempBuff);AVIOContext *avioCtx = NULL;int errCode = -1;/** Create and initialize a AVIOContext for accessing the* resource indicated by url.* */if ((errCode = avio_open(&avioCtx, pSrcFileName, AVIO_FLAG_READ)) < 0) {av_log(NULL, AV_LOG_ERROR, "Coud not open file %s\n", pSrcFileName);exit(3);}unsigned char strBuff[1024];avio_read(avioCtx, strBuff, sizeof(strBuff));avio_close(avioCtx);av_log(NULL, AV_LOG_DEBUG, "read file content:%s", strBuff);memset(tempBuff, 0, sizeof(tempBuff));snprintf(tempBuff, sizeof(tempBuff), "rm %s", pSrcFileName);system(tempBuff);return 0; }執行結果如下:
./ffmpeg_io_read test.txt read file content:hello world!總結
以上是生活随笔為你收集整理的FFmpeg中的日志以及avio实现对文件的读写功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 23种设计模式C++源码与UML实现--
- 下一篇: FFmpeg--av_register_