日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

FFmepg 多线程解码历程

發布時間:2023/12/13 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FFmepg 多线程解码历程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

FFmepg 多線程解碼歷程 - 1:validate_thread_parameters


/**
?* Set the threading algorithms used.//設置線程的使用算法
?* Threading requires more than one thread.//需要一個以上的線程
?* Frame threading requires entire frames to be passed to the codec,//幀線程需要整個幀被傳遞到編碼解碼器
?* and introduces extra decoding delay, so is incompatible with low_delay.// 并引入了額外的解碼延遲,所以是不符合low_delay
?* @param avctx The context.
?*/

?//有效的線程參數

static void validate_thread_parameters(AVCodecContext *avctx)
{

??? //實現幀線程支持,需要在配置codec的時候設置codec的capabilities,flags,flags2
??? int frame_threading_supported = (avctx->codec->capabilities & CODEC_CAP_FRAME_THREADS)
??????????????????????????????? && !(avctx->flags & CODEC_FLAG_TRUNCATED)
??????????????????????????????? && !(avctx->flags & CODEC_FLAG_LOW_DELAY)
??????????????????????????????? && !(avctx->flags2 & CODEC_FLAG2_CHUNKS);
??? if (avctx->thread_count == 1) {??? //多線程要在雙核以上的機器上才行
??????? avctx->active_thread_type = 0;
??? } else if (frame_threading_supported && (avctx->thread_type & FF_THREAD_FRAME)) {//? 在codec初始化的時候設置avctx->thread_type |=FF_THREAD_FRAME
??????? avctx->active_thread_type = FF_THREAD_FRAME;?? //線程的類型設置為幀并行
??? } else if (avctx->codec->capabilities & CODEC_CAP_SLICE_THREADS &&
?????????????? avctx->thread_type & FF_THREAD_SLICE) {? //同樣的要實現片級并行則需要在codec初始化的時候設置條件
??????? avctx->active_thread_type = FF_THREAD_SLICE;
??? } else if (!(avctx->codec->capabilities & CODEC_CAP_AUTO_THREADS)) {
??????? avctx->thread_count?????? = 1;
??????? avctx->active_thread_type = 0;
??? }

??? if (avctx->thread_count > MAX_AUTO_THREADS)
??????? av_log(avctx, AV_LOG_WARNING,
?????????????? "Application has requested %d threads. Using a thread count greater than %d is not recommended.\n",
?????????????? avctx->thread_count, MAX_AUTO_THREADS);
}

注釋:

如果不知到幀與片 可以查看之前的轉載文章? http://blog.csdn.net/jwzhangjie/article/details/8739139


FFmepg 多線程解碼歷程 - 2 :avcodec_decode_video2

//解碼函數

int attribute_align_arg avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,

????????????????????????????????????????????? int *got_picture_ptr,
????????????????????????????????????????????? const AVPacket *avpkt)
{
??? AVCodecInternal *avci = avctx->internal;
??? int ret;
??? // copy to ensure we do not change avpkt
??? AVPacket tmp = *avpkt;

??? if (avctx->codec->type != AVMEDIA_TYPE_VIDEO) {?? //如果不是視頻類型,則退出
??????? av_log(avctx, AV_LOG_ERROR, "Invalid media type for video\n");
??????? return AVERROR(EINVAL);
??? }

??? *got_picture_ptr = 0;? /
??? if ((avctx->coded_width || avctx->coded_height) && av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx))
??????? return AVERROR(EINVAL);

??? avcodec_get_frame_defaults(picture);

??? if (!avctx->refcounted_frames)
??????? av_frame_unref(&avci->to_free);

//如果是幀并行解碼的話

//需要在codec初始化的時候設置codec->capabilities |= CODEC_CAP_DELAY,查看注釋,設置avctx->active_thread_type |= FF_THREAD_FRAME

??? if ((avctx->codec->capabilities & CODEC_CAP_DELAY) || avpkt->size || (avctx->active_thread_type & FF_THREAD_FRAME)) {
??????? int did_split = av_packet_split_side_data(&tmp);
??????? apply_param_change(avctx, &tmp);

??????? avctx->pkt = &tmp;

//需要配置configure? --enable-pthreads(我現在最新的默認生成的config.h就是#define? HAVE_THREADS 1)? ,設置avctx->active_thread_type |= FF_THREAD_FRAME

??????? if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME)
??????????? ret = ff_thread_decode_frame(avctx, picture, got_picture_ptr,&tmp);//進入幀級并行解碼
??????? else {//進入單線程解碼
??????????? ret = avctx->codec->decode(avctx, picture, got_picture_ptr, &tmp);
??????????? picture->pkt_dts = avpkt->dts;

??????????? if(!avctx->has_b_frames){
??????????????? av_frame_set_pkt_pos(picture, avpkt->pos);
??????????? }
??????????? //FIXME these should be under if(!avctx->has_b_frames)
??????????? /* get_buffer is supposed to set frame parameters */
??????????? if (!(avctx->codec->capabilities & CODEC_CAP_DR1)) {
??????????????? if (!picture->sample_aspect_ratio.num)??? picture->sample_aspect_ratio = avctx->sample_aspect_ratio;
??????????????? if (!picture->width)????????????????????? picture->width?????????????? = avctx->width;
??????????????? if (!picture->height)???????????????????? picture->height????????????? = avctx->height;
??????????????? if (picture->format == AV_PIX_FMT_NONE)?? picture->format????????????? = avctx->pix_fmt;
??????????? }
??????? }
??????? add_metadata_from_side_data(avctx, picture);

??????? emms_c(); //needed to avoid an emms_c() call before every return;

??????? avctx->pkt = NULL;
??????? if (did_split) {
??????????? ff_packet_free_side_data(&tmp);
??????????? if(ret == tmp.size)
??????????????? ret = avpkt->size;
??????? }

??????? if (ret < 0 && picture->data[0])
??????????? av_frame_unref(picture);

??????? if (*got_picture_ptr) {
??????????? if (!avctx->refcounted_frames) {
??????????????? avci->to_free = *picture;
??????????????? avci->to_free.extended_data = avci->to_free.data;
??????????? }

??????????? avctx->frame_number++;
??????????? av_frame_set_best_effort_timestamp(picture,
?????????????????????????????????????????????? guess_correct_pts(avctx,
???????????????????????????????????????????????????????????????? picture->pkt_pts,
???????????????????????????????????????????????????????????????? picture->pkt_dts));
??????? }
??? } else
??????? ret = 0;

??? /* many decoders assign whole AVFrames, thus overwriting extended_data;

???? * make sure it's set correctly */

//許多解碼器分配整個的AVFrames ,從而覆蓋extended_data相關

??? picture->extended_data = picture->data;

??? return ret;
}

?

注釋:

/**
?* Encoder or decoder requires flushing with NULL input at the end in order to
?* give the complete and correct output.
?*
?* NOTE: If this flag is not set, the codec is guaranteed to never be fed with
?*?????? with NULL data. The user can still send NULL data to the public encode
?*?????? or decode function, but libavcodec will not pass it along to the codec
?*?????? unless this flag is set.
?*
?* Decoders:
?* The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL,
?* avpkt->size=0 at the end to get the delayed data until the decoder no longer
?* returns frames.
?*
?* Encoders:
?* The encoder needs to be fed with NULL data at the end of encoding until the
?* encoder no longer returns data.
?*
?* NOTE: For encoders implementing the AVCodec.encode2() function, setting this
?*?????? flag also means that the encoder must set the pts and duration for
?*?????? each output packet. If this flag is not set, the pts and duration will
?*?????? be determined by libavcodec from the input frame.
?*/

#define CODEC_CAP_DELAY?????????? 0x0020

FFmepg 多線程解碼歷程 - 3: int ff_thread_decode_frame

//幀級解碼函數,在avcodec_open2的時候,就會判斷片還是幀解碼,分析見下一篇

int ff_thread_decode_frame(AVCodecContext *avctx,

?????????????????????????? AVFrame *picture, int *got_picture_ptr,
?????????????????????????? AVPacket *avpkt)
{
??? FrameThreadContext *fctx = avctx->thread_opaque; //thread_opaque見注釋1
??? int finished = fctx->next_finished; //從返回結果輸出的下一個內容
??? PerThreadContext *p; //查看注釋2
??? int err;

??? /*

???? * Submit a packet to the next decoding thread.
*提交數據包發送到下一個解碼線程

???? */

??? p = &fctx->threads[fctx->next_decoding];
??? err = update_context_from_user(p->avctx, avctx); //將用戶提交的avctx復制到p->avctx里面
??? if (err) return err;
??? err = submit_packet(p, avpkt);
??? if (err) return err;

??? /*

???? * If we're still receiving the initial packets, don't return a frame.

???? *如果我們仍然接收的初步數據包,不返回幀

*/


??? if (fctx->delaying) {
??????? if (fctx->next_decoding >= (avctx->thread_count-1)) fctx->delaying = 0;

??????? *got_picture_ptr=0;
??????? if (avpkt->size)
??????????? return avpkt->size;
??? }

??? /*
???? * Return the next available frame from the oldest thread.//返回下一個可用幀從最早的線程
???? * If we're at the end of the stream, then we have to skip threads that
???? * didn't output a frame, because we don't want to accidentally signal
???? * EOF (avpkt->size == 0 && *got_picture_ptr == 0).//因為我們不希望發生意外信號EOF,所以在流的最后,我們必須跳過線程,而不輸出幀
???? *
/

??? do {
??????? p = &fctx->threads[finished++];

??????? if (p->state != STATE_INPUT_READY) {
??????????? pthread_mutex_lock(&p->progress_mutex);
??????????? while (p->state != STATE_INPUT_READY) //如果數據的狀態不是STATE_INPUT_READY,線程進行等待,直到線程pthread_cond_signal(&p->progress_cond);
??????????????? pthread_cond_wait(&p->output_cond, &p->progress_mutex);
??????????? pthread_mutex_unlock(&p->progress_mutex);
??????? }

??????? av_frame_move_ref(picture, &p->frame);
??????? *got_picture_ptr = p->got_frame;
??????? picture->pkt_dts = p->avpkt.dts;

??????? /*
???????? * A later call with avkpt->size == 0 may loop over all threads,
???????? * including this one, searching for a frame to return before being
???????? * stopped by the "finished != fctx->next_finished" condition.
???????? * Make sure we don't mistakenly return the same frame again.
???????? */
??????? p->got_frame = 0;

??????? if (finished >= avctx->thread_count) finished = 0;
??? } while (!avpkt->size && !*got_picture_ptr && finished != fctx->next_finished);

??? update_context_from_thread(avctx, p->avctx, 1);

??? if (fctx->next_decoding >= avctx->thread_count) fctx->next_decoding = 0;

??? fctx->next_finished = finished;

??? /* return the size of the consumed packet if no error occurred */
??? return (p->result >= 0) ? avpkt->size : p->result;
}

注釋:

1.

/**
???? * thread opaque
???? * Can be used by execute() to store some per AVCodecContext stuff.

//能夠使用execute()函數來存儲每個AVCodecContext數據
???? * - encoding: set by execute()
???? * - decoding: set by execute()
???? */
??? void *thread_opaque;

2.

/**
?* Context used by codec threads and stored in their AVCodecContext thread_opaque.

?*上下文所使用的編解碼器線程和存儲在他們的AVCodecContext thread_opaque
?*/
typedef struct PerThreadContext {
??? struct FrameThreadContext *parent;

??? pthread_t????? thread;
??? int??????????? thread_init;
??? pthread_cond_t input_cond;????? ///< Used to wait for a new packet from the main thread.從主線程等待一個新的數據包。
??? pthread_cond_t progress_cond;?? ///< Used by child threads to wait for progress to change.
??? pthread_cond_t output_cond;???? ///< Used by the main thread to wait for frames to finish.用于由主線程等待幀來完成

??? pthread_mutex_t mutex;????????? ///< Mutex used to protect the contents of the PerThreadContext.
??? pthread_mutex_t progress_mutex; ///< Mutex used to protect frame progress values and progress_cond.

??? AVCodecContext *avctx;????????? ///< Context used to decode packets passed to this thread.

??? AVPacket?????? avpkt;?????????? ///< Input packet (for decoding) or output (for encoding).
??? uint8_t?????? *buf;???????????? ///< backup storage for packet data when the input packet is not refcounted
??? int??????????? allocated_buf_size; ///< Size allocated for buf

??? AVFrame frame;????????????????? ///< Output frame (for decoding) or input (for encoding).
??? int???? got_frame;????????????? ///< The output of got_picture_ptr from the last avcodec_decode_video() call.
??? int???? result;???????????????? ///< The result of the last codec decode/encode() call.

??? enum {?? //這個可以看之前文章中提到的幀級解碼狀態圖
??????? STATE_INPUT_READY,????????? ///< Set when the thread is awaiting a packet.
??????? STATE_SETTING_UP,?????????? ///< Set before the codec has called ff_thread_finish_setup().
??????? STATE_GET_BUFFER,?????????? /**<
???????????????????????????????????? * Set when the codec calls get_buffer().
???????????????????????????????????? * State is returned to STATE_SETTING_UP afterwards.
???????????????????????????????????? */
??????? STATE_SETUP_FINISHED??????? ///< Set after the codec has called ff_thread_finish_setup().
??? } state;

??? /**
???? * Array of frames passed to ff_thread_release_buffer().
???? * Frames are released after all threads referencing them are finished.
???? */
??? AVFrame *released_buffers;
??? int? num_released_buffers;
??? int????? released_buffers_allocated;

??? AVFrame *requested_frame;?????? ///< AVFrame the codec passed to get_buffer()
??? int????? requested_flags;?????? ///< flags passed to get_buffer() for requested_frame
} PerThreadContext;


FFmepg 多線程解碼歷程 - 4:avcodec_open2

//在初始化codec后,接下來就是打開解碼器
int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options)
{
??? int ret = 0;
??? AVDictionary *tmp = NULL;

??? if (avcodec_is_open(avctx))? //返回avctx-》internal,見注釋1
??????? return 0;

??? if ((!codec && !avctx->codec)) {
??????? av_log(avctx, AV_LOG_ERROR, "No codec provided to avcodec_open2()\n");
??????? return AVERROR(EINVAL);
??? }
??? if ((codec && avctx->codec && codec != avctx->codec)) {
??????? av_log(avctx, AV_LOG_ERROR, "This AVCodecContext was allocated for %s, "
??????????????????????????????????? "but %s passed to avcodec_open2()\n", avctx->codec->name, codec->name);
??????? return AVERROR(EINVAL);
??? }
??? if (!codec)
??????? codec = avctx->codec;
//判斷額外數據,在硬解嗎h264的時候必須人為設置sps pps給extradata
??? if (avctx->extradata_size < 0 || avctx->extradata_size >= FF_MAX_EXTRADATA_SIZE)
??????? return AVERROR(EINVAL);

??? if (options)?? //一般options設置NULL
??????? av_dict_copy(&tmp, *options, 0);

??? ret = ff_lock_avcodec(avctx);
??? if (ret < 0)
??????? return ret;

??? avctx->internal = av_mallocz(sizeof(AVCodecInternal));
??? if (!avctx->internal) {
??????? ret = AVERROR(ENOMEM);
??????? goto end;
??? }

??? avctx->internal->pool = av_mallocz(sizeof(*avctx->internal->pool));
??? if (!avctx->internal->pool) {
??????? ret = AVERROR(ENOMEM);
??????? goto free_and_end;
??? }

??? if (codec->priv_data_size > 0) {
??????? if (!avctx->priv_data) {
??????????? avctx->priv_data = av_mallocz(codec->priv_data_size);
??????????? if (!avctx->priv_data) {
??????????????? ret = AVERROR(ENOMEM);
??????????????? goto end;
??????????? }
??????????? if (codec->priv_class) {
??????????????? *(const AVClass **)avctx->priv_data = codec->priv_class;
??????????????? av_opt_set_defaults(avctx->priv_data);
??????????? }
??????? }
??????? if (codec->priv_class && (ret = av_opt_set_dict(avctx->priv_data, &tmp)) < 0)
??????????? goto free_and_end;
??? } else {
??????? avctx->priv_data = NULL;
??? } //上面主要是分配內存
??? if ((ret = av_opt_set_dict(avctx, &tmp)) < 0)
??????? goto free_and_end;

??? // only call avcodec_set_dimensions() for non H.264/VP6F codecs so as not to overwrite previously setup dimensions
??? if (!(avctx->coded_width && avctx->coded_height && avctx->width && avctx->height &&
????????? (avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_VP6F))) {
??? if (avctx->coded_width && avctx->coded_height)
??????? avcodec_set_dimensions(avctx, avctx->coded_width, avctx->coded_height);
??? else if (avctx->width && avctx->height)
??????? avcodec_set_dimensions(avctx, avctx->width, avctx->height);
??? }

??? if ((avctx->coded_width || avctx->coded_height || avctx->width || avctx->height)
??????? && (? av_image_check_size(avctx->coded_width, avctx->coded_height, 0, avctx) < 0
?????????? || av_image_check_size(avctx->width,?????? avctx->height,?????? 0, avctx) < 0)) {
??????? av_log(avctx, AV_LOG_WARNING, "Ignoring invalid width/height values\n");
??????? avcodec_set_dimensions(avctx, 0, 0);
??? }

?? ? /* if the decoder init function was already called previously,如果解碼器的init函數已經調用過
???? * free the already allocated subtitle_header before overwriting it 釋放已經分配subtitle_header ,在它覆蓋前
*/

??? if (av_codec_is_decoder(codec))
??????? av_freep(&avctx->subtitle_header);

??? if (avctx->channels > FF_SANE_NB_CHANNELS) {
??????? ret = AVERROR(EINVAL);
??????? goto free_and_end;
??? }

??? avctx->codec = codec;
??? if ((avctx->codec_type == AVMEDIA_TYPE_UNKNOWN || avctx->codec_type == codec->type) &&
??????? avctx->codec_id == AV_CODEC_ID_NONE) {
??????? avctx->codec_type = codec->type;
??????? avctx->codec_id?? = codec->id;
??? }
??? if (avctx->codec_id != codec->id || (avctx->codec_type != codec->type
???????????????????????????????????????? && avctx->codec_type != AVMEDIA_TYPE_ATTACHMENT)) {
??????? av_log(avctx, AV_LOG_ERROR, "Codec type or id mismatches\n");
??????? ret = AVERROR(EINVAL);
??????? goto free_and_end;
??? }
??? avctx->frame_number = 0;
??? avctx->codec_descriptor = avcodec_descriptor_get(avctx->codec_id);

??? if (avctx->codec->capabilities & CODEC_CAP_EXPERIMENTAL &&
??????? avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
??????? const char *codec_string = av_codec_is_encoder(codec) ? "encoder" : "decoder";
??????? AVCodec *codec2;
??????? av_log(NULL, AV_LOG_ERROR,
?????????????? "The %s '%s' is experimental but experimental codecs are not enabled, "
?????????????? "add '-strict %d' if you want to use it.\n",
?????????????? codec_string, codec->name, FF_COMPLIANCE_EXPERIMENTAL);
??????? codec2 = av_codec_is_encoder(codec) ? avcodec_find_encoder(codec->id) : avcodec_find_decoder(codec->id);
??????? if (!(codec2->capabilities & CODEC_CAP_EXPERIMENTAL))
??????????? av_log(NULL, AV_LOG_ERROR, "Alternatively use the non experimental %s '%s'.\n",
??????????????? codec_string, codec2->name);
??????? ret = AVERROR_EXPERIMENTAL;
??????? goto free_and_end;
??? }

??? if (avctx->codec_type == AVMEDIA_TYPE_AUDIO &&
??????? (!avctx->time_base.num || !avctx->time_base.den)) {
??????? avctx->time_base.num = 1;
??????? avctx->time_base.den = avctx->sample_rate;
??? }

??? if (!HAVE_THREADS)
??????? av_log(avctx, AV_LOG_WARNING, "Warning: not compiled with thread support, using thread emulation\n");

??? if (CONFIG_FRAME_THREAD_ENCODER) {
??????? ff_unlock_avcodec(); //we will instanciate a few encoders thus kick the counter to prevent false detection of a problem
??????? ret = ff_frame_thread_encoder_init(avctx, options ? *options : NULL);
??????? ff_lock_avcodec(avctx);
??????? if (ret < 0)
??????????? goto free_and_end;
??? }
//幀線程編碼
??? if (HAVE_THREADS && !avctx->thread_opaque
??????? && !(avctx->internal->frame_thread_encoder && (avctx->active_thread_type&FF_THREAD_FRAME))) {
??????? ret = ff_thread_init(avctx);//會根據用戶設置不同的變量來判斷是片,幀,來初始化線程
??????? if (ret < 0) {
??????????? goto free_and_end;
??????? }
??? }
??? if (!HAVE_THREADS && !(codec->capabilities & CODEC_CAP_AUTO_THREADS))
??????? avctx->thread_count = 1;

??? if (avctx->codec->max_lowres < avctx->lowres || avctx->lowres < 0) {
??????? av_log(avctx, AV_LOG_ERROR, "The maximum value for lowres supported by the decoder is %d\n",
?????????????? avctx->codec->max_lowres);
??????? ret = AVERROR(EINVAL);
??????? goto free_and_end;

??? }

//下面就會根據是編碼器還是解碼器來初始化


??? if (av_codec_is_encoder(avctx->codec)) {
??????? int i;
??????? if (avctx->codec->sample_fmts) {
??????????? for (i = 0; avctx->codec->sample_fmts[i] != AV_SAMPLE_FMT_NONE; i++) {
??????????????? if (avctx->sample_fmt == avctx->codec->sample_fmts[i])
??????????????????? break;
??????????????? if (avctx->channels == 1 &&
??????????????????? av_get_planar_sample_fmt(avctx->sample_fmt) ==
??????????????????? av_get_planar_sample_fmt(avctx->codec->sample_fmts[i])) {
??????????????????? avctx->sample_fmt = avctx->codec->sample_fmts[i];
??????????????????? break;
??????????????? }
??????????? }
??????????? if (avctx->codec->sample_fmts[i] == AV_SAMPLE_FMT_NONE) {
??????????????? char buf[128];
??????????????? snprintf(buf, sizeof(buf), "%d", avctx->sample_fmt);
??????????????? av_log(avctx, AV_LOG_ERROR, "Specified sample format %s is invalid or not supported\n",
?????????????????????? (char *)av_x_if_null(av_get_sample_fmt_name(avctx->sample_fmt), buf));
??????????????? ret = AVERROR(EINVAL);
??????????????? goto free_and_end;
??????????? }
??????? }
??????? if (avctx->codec->pix_fmts) {
??????????? for (i = 0; avctx->codec->pix_fmts[i] != AV_PIX_FMT_NONE; i++)
??????????????? if (avctx->pix_fmt == avctx->codec->pix_fmts[i])
??????????????????? break;
??????????? if (avctx->codec->pix_fmts[i] == AV_PIX_FMT_NONE
??????????????? && !((avctx->codec_id == AV_CODEC_ID_MJPEG || avctx->codec_id == AV_CODEC_ID_LJPEG)
???????????????????? && avctx->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
??????????????? char buf[128];
??????????????? snprintf(buf, sizeof(buf), "%d", avctx->pix_fmt);
??????????????? av_log(avctx, AV_LOG_ERROR, "Specified pixel format %s is invalid or not supported\n",
?????????????????????? (char *)av_x_if_null(av_get_pix_fmt_name(avctx->pix_fmt), buf));
??????????????? ret = AVERROR(EINVAL);
??????????????? goto free_and_end;
??????????? }
??????? }
??????? if (avctx->codec->supported_samplerates) {
??????????? for (i = 0; avctx->codec->supported_samplerates[i] != 0; i++)
??????????????? if (avctx->sample_rate == avctx->codec->supported_samplerates[i])
??????????????????? break;
??????????? if (avctx->codec->supported_samplerates[i] == 0) {
??????????????? av_log(avctx, AV_LOG_ERROR, "Specified sample rate %d is not supported\n",
?????????????????????? avctx->sample_rate);
??????????????? ret = AVERROR(EINVAL);
??????????????? goto free_and_end;
??????????? }
??????? }
??????? if (avctx->codec->channel_layouts) {
??????????? if (!avctx->channel_layout) {
??????????????? av_log(avctx, AV_LOG_WARNING, "Channel layout not specified\n");
??????????? } else {
??????????????? for (i = 0; avctx->codec->channel_layouts[i] != 0; i++)
??????????????????? if (avctx->channel_layout == avctx->codec->channel_layouts[i])
??????????????????????? break;
??????????????? if (avctx->codec->channel_layouts[i] == 0) {
??????????????????? char buf[512];
??????????????????? av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout);
??????????????????? av_log(avctx, AV_LOG_ERROR, "Specified channel layout '%s' is not supported\n", buf);
??????????????????? ret = AVERROR(EINVAL);
??????????????????? goto free_and_end;
??????????????? }
??????????? }
??????? }
??????? if (avctx->channel_layout && avctx->channels) {
??????????? int channels = av_get_channel_layout_nb_channels(avctx->channel_layout);
??????????? if (channels != avctx->channels) {
??????????????? char buf[512];
??????????????? av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout);
??????????????? av_log(avctx, AV_LOG_ERROR,
?????????????????????? "Channel layout '%s' with %d channels does not match number of specified channels %d\n",
?????????????????????? buf, channels, avctx->channels);
??????????????? ret = AVERROR(EINVAL);
??????????????? goto free_and_end;
??????????? }
??????? } else if (avctx->channel_layout) {
??????????? avctx->channels = av_get_channel_layout_nb_channels(avctx->channel_layout);
??????? }
??????? if(avctx->codec_type == AVMEDIA_TYPE_VIDEO &&
?????????? avctx->codec_id != AV_CODEC_ID_PNG // For mplayer
??????? ) {
??????????? if (avctx->width <= 0 || avctx->height <= 0) {
??????????????? av_log(avctx, AV_LOG_ERROR, "dimensions not set\n");
??????????????? ret = AVERROR(EINVAL);
??????????????? goto free_and_end;
??????????? }
??????? }
??????? if (?? (avctx->codec_type == AVMEDIA_TYPE_VIDEO || avctx->codec_type == AVMEDIA_TYPE_AUDIO)
??????????? && avctx->bit_rate>0 && avctx->bit_rate<1000) {
??????????? av_log(avctx, AV_LOG_WARNING, "Bitrate %d is extremely low, maybe you mean %dk\n", avctx->bit_rate, avctx->bit_rate);
??????? }

??????? if (!avctx->rc_initial_buffer_occupancy)
??????????? avctx->rc_initial_buffer_occupancy = avctx->rc_buffer_size * 3 / 4;
??? }

??? avctx->pts_correction_num_faulty_pts =
??? avctx->pts_correction_num_faulty_dts = 0;
??? avctx->pts_correction_last_pts =
??? avctx->pts_correction_last_dts = INT64_MIN;

??? if (?? avctx->codec->init && (!(avctx->active_thread_type&FF_THREAD_FRAME)
??????? || avctx->internal->frame_thread_encoder)) {
??????? ret = avctx->codec->init(avctx);
??????? if (ret < 0) {
??????????? goto free_and_end;
??????? }
??? }

??? ret=0;


//上面部分是判斷codec是否是編碼器,然后如果是編碼器則進行選擇編碼的方式,這里我們只討論解碼,下面的解碼器也是一樣,根據不同的條件,進行編碼初始化


??? if (av_codec_is_decoder(avctx->codec)) {
??????? if (!avctx->bit_rate)
??????????? avctx->bit_rate = get_bit_rate(avctx);//如果沒有設置bit_rate則會更加avctx類型將avctx->bit_rate復制給
??????? /* validate channel layout from the decoder */
??????? if (avctx->channel_layout) {
??????????? int channels = av_get_channel_layout_nb_channels(avctx->channel_layout);
??????????? if (!avctx->channels)
??????????????? avctx->channels = channels;
??????????? else if (channels != avctx->channels) {
??????????????? char buf[512];
??????????????? av_get_channel_layout_string(buf, sizeof(buf), -1, avctx->channel_layout);
??????????????? av_log(avctx, AV_LOG_WARNING,
?????????????????????? "Channel layout '%s' with %d channels does not match specified number of channels %d: "
?????????????????????? "ignoring specified channel layout\n",
?????????????????????? buf, channels, avctx->channels);
??????????????? avctx->channel_layout = 0;
??????????? }
??????? }
??????? if (avctx->channels && avctx->channels < 0 ||
??????????? avctx->channels > FF_SANE_NB_CHANNELS) {
??????????? ret = AVERROR(EINVAL);
??????????? goto free_and_end;
??????? }
??????? if (avctx->sub_charenc) {
??????????? if (avctx->codec_type != AVMEDIA_TYPE_SUBTITLE) {
??????????????? av_log(avctx, AV_LOG_ERROR, "Character encoding is only "
?????????????????????? "supported with subtitles codecs\n");
??????????????? ret = AVERROR(EINVAL);
??????????????? goto free_and_end;
??????????? } else if (avctx->codec_descriptor->props & AV_CODEC_PROP_BITMAP_SUB) {
??????????????? av_log(avctx, AV_LOG_WARNING, "Codec '%s' is bitmap-based, "
?????????????????????? "subtitles character encoding will be ignored\n",
?????????????????????? avctx->codec_descriptor->name);
??????????????? avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_DO_NOTHING;
??????????? } else {
??????????????? /* input character encoding is set for a text based subtitle
???????????????? * codec at this point */
??????????????? if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_AUTOMATIC)
??????????????????? avctx->sub_charenc_mode = FF_SUB_CHARENC_MODE_PRE_DECODER;

??????????????? if (avctx->sub_charenc_mode == FF_SUB_CHARENC_MODE_PRE_DECODER) {
#if CONFIG_ICONV
??????????????????? iconv_t cd = iconv_open("UTF-8", avctx->sub_charenc);
??????????????????? if (cd == (iconv_t)-1) {
??????????????????????? av_log(avctx, AV_LOG_ERROR, "Unable to open iconv context "
?????????????????????????????? "with input character encoding \"%s\"\n", avctx->sub_charenc);
??????????????????????? ret = AVERROR(errno);
??????????????????????? goto free_and_end;
??????????????????? }
??????????????????? iconv_close(cd);
#else
??????????????????? av_log(avctx, AV_LOG_ERROR, "Character encoding subtitles "
?????????????????????????? "conversion needs a libavcodec built with iconv support "
?????????????????????????? "for this codec\n");
??????????????????? ret = AVERROR(ENOSYS);
??????????????????? goto free_and_end;
#endif
??????????????? }
??????????? }
??????? }
??? }
end:
??? ff_unlock_avcodec();
??? if (options) {
??????? av_dict_free(options);
??????? *options = tmp;
??? }

??? return ret;
free_and_end:
??? av_dict_free(&tmp);
??? av_freep(&avctx->priv_data);
??? if (avctx->internal)
??????? av_freep(&avctx->internal->pool);
??? av_freep(&avctx->internal);
??? avctx->codec = NULL;
??? goto end;
}

注釋:

1.?/**
???? * Private context used for internal data.
???? *私有的上下文內容用于內部數據
???? * Unlike priv_data, this is not codec-specific. It is used in general
???? * libavcodec functions.

*不像priv_data ,這是不特定的編解碼器。這是用在一般libavcodec的功能
???? */
??? struct AVCodecInternal *internal;

FFmepg 多線程解碼歷程 - 5: ff_thread_init

//用來判斷是幀還是片線程初始化
int ff_thread_init(AVCodecContext *avctx)
{
??? if (avctx->thread_opaque) {
??????? av_log(avctx, AV_LOG_ERROR, "avcodec_thread_init is ignored after avcodec_open\n");
??????? return -1;
??? }

#if HAVE_W32THREADS
??? w32thread_init();
#endif

??? if (avctx->codec) {
?? ??? ? //有效的線程參數,將會設置avctx->active_thread_type,進而判斷進入下面if的哪個條件
??????? validate_thread_parameters(avctx);// 查看FFmepg 多線程解碼歷程 - 1:validate_thread_parameters 講解
?? ??? ?
??????? if (avctx->active_thread_type&FF_THREAD_SLICE)
??????????? return thread_init(avctx);
??????? else if (avctx->active_thread_type&FF_THREAD_FRAME)
??????????? return frame_thread_init(avctx);? //下一篇講解frame_thread_init的具體內容
??? }

??? return 0;
}

FFmepg 多線程解碼歷程 - 6:frame_thread_init

//ff_thread_init選擇幀線程初始化,就會進入frame_thread_init

static int frame_thread_init(AVCodecContext *avctx)

{
??? int thread_count = avctx->thread_count;
??? const AVCodec *codec = avctx->codec;
??? AVCodecContext *src = avctx;
??? FrameThreadContext *fctx;
??? int i, err = 0;
//如果我們在初始化codec的時候沒有設置thread_count或者設置為0,則就會自動根據手機設備來獲取
??? if (!thread_count) {
??????? int nb_cpus = ff_get_logical_cpus(avctx);
??????? if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || avctx->debug_mv)
??????????? nb_cpus = 1;
??????? // use number of cores + 1 as thread count if there is more than one
??????? if (nb_cpus > 1)
??????????? thread_count = avctx->thread_count = FFMIN(nb_cpus + 1, MAX_AUTO_THREADS);? //#define FFMIN(a,b) ((a) > (b) ? (b) : (a))
??????? else
??????????? thread_count = avctx->thread_count = 1;
??? }

??? if (thread_count <= 1) {? //如果thread_count <= 1那么即使進入幀級線程初始化,在解碼的時候也不會調用幀級解碼函數的
??????? avctx->active_thread_type = 0;
??????? return 0;
??? }

??? avctx->thread_opaque = fctx = av_mallocz(sizeof(FrameThreadContext));

??? fctx->threads = av_mallocz(sizeof(PerThreadContext) * thread_count);? //相當與初始化線程池,個數就是thread_count
??? pthread_mutex_init(&fctx->buffer_mutex, NULL);
??? fctx->delaying = 1;

??? for (i = 0; i < thread_count; i++) {
??????? AVCodecContext *copy = av_malloc(sizeof(AVCodecContext));
??????? PerThreadContext *p? = &fctx->threads[i];

??????? pthread_mutex_init(&p->mutex, NULL);
??????? pthread_mutex_init(&p->progress_mutex, NULL);
??????? pthread_cond_init(&p->input_cond, NULL);
??????? pthread_cond_init(&p->progress_cond, NULL);
??????? pthread_cond_init(&p->output_cond, NULL);

??????? p->parent = fctx;
??????? p->avctx? = copy;

??????? if (!copy) {
??????????? err = AVERROR(ENOMEM);
??????????? goto error;
??????? }

??????? *copy = *src;
??????? copy->thread_opaque = p;
??????? copy->pkt = &p->avpkt;

??????? if (!i) {
??????????? src = copy;

??????????? if (codec->init)
??????????????? err = codec->init(copy);
?? ??? ?//更新下一個線程的AVCodecContext參考線程的上下文中的值
??????????? update_context_from_thread(avctx, copy, 1);
??????? } else {
??????????? copy->priv_data = av_malloc(codec->priv_data_size);
??????????? if (!copy->priv_data) {
??????????????? err = AVERROR(ENOMEM);
??????????????? goto error;
??????????? }
??????????? memcpy(copy->priv_data, src->priv_data, codec->priv_data_size);
??????????? copy->internal = av_malloc(sizeof(AVCodecInternal));
??????????? if (!copy->internal) {
??????????????? err = AVERROR(ENOMEM);
??????????????? goto error;
??????????? }
??????????? *copy->internal = *src->internal;
??????????? copy->internal->is_copy = 1;

??????????? if (codec->init_thread_copy)
??????????????? err = codec->init_thread_copy(copy);
??????? }

??????? if (err) goto error;
/ //下面出創建線程,調用frame_worker_thread
??????? err = AVERROR(pthread_create(&p->thread, NULL, frame_worker_thread, p));
??????? p->thread_init= !err;
??????? if(!p->thread_init)
??????????? goto error;
??? }

??? return 0;

error:
??? frame_thread_free(avctx, i+1);

??? return err;
}


FFmepg 多線程解碼歷程 - 7:submit_packet

//在ff_thread_decode_frame中會調用submit_packet將碼流交給對應的解碼線程,來實現線程狀態的改變,具體的流程圖見下面圖

static int submit_packet(PerThreadContext *p, AVPacket *avpkt)

{
??? FrameThreadContext *fctx = p->parent;
??? PerThreadContext *prev_thread = fctx->prev_thread;
??? const AVCodec *codec = p->avctx->codec;

??? if (!avpkt->size && !(codec->capabilities & CODEC_CAP_DELAY)) return 0;

??? pthread_mutex_lock(&p->mutex);

??? release_delayed_buffers(p);

??? if (prev_thread) {
??????? int err;
??????? if (prev_thread->state == STATE_SETTING_UP) {
??????????? pthread_mutex_lock(&prev_thread->progress_mutex);
??????????? while (prev_thread->state == STATE_SETTING_UP)? //判斷之前的線程狀態為STATE_SETTING_UP的時候,進行線程的等待,
??????????????? pthread_cond_wait(&prev_thread->progress_cond, &prev_thread->progress_mutex);
??????????? pthread_mutex_unlock(&prev_thread->progress_mutex);
??????? }

??????? err = update_context_from_thread(p->avctx, prev_thread->avctx, 0);//如果之前的線程狀態變為STATE_SETUP_FINISHED,然后從線程中哦功能更新內容
??????? if (err) {
??????????? pthread_mutex_unlock(&p->mutex);
??????????? return err;
??????? }
??? }

??? av_buffer_unref(&p->avpkt.buf);
??? p->avpkt = *avpkt;
??? if (avpkt->buf)
??????? p->avpkt.buf = av_buffer_ref(avpkt->buf);
??? else {
??????? av_fast_malloc(&p->buf, &p->allocated_buf_size, avpkt->size + FF_INPUT_BUFFER_PADDING_SIZE);
??????? p->avpkt.data = p->buf;
??????? memcpy(p->buf, avpkt->data, avpkt->size);
??????? memset(p->buf + avpkt->size, 0, FF_INPUT_BUFFER_PADDING_SIZE);
??? }

??? p->state = STATE_SETTING_UP;
??? pthread_cond_signal(&p->input_cond);//發送碼流輸入準備好的信號給解碼線程pthread_cond_waite(&p->input_cond),讓解碼線程
??? pthread_mutex_unlock(&p->mutex);

??? /*
???? * If the client doesn't have a thread-safe get_buffer(),
???? * then decoding threads call back to the main thread,
???? * and it calls back to the client here.
???? */

??? if (!p->avctx->thread_safe_callbacks && (
#if FF_API_GET_BUFFER
???????? p->avctx->get_buffer ||
#endif
???????? p->avctx->get_buffer2 != avcodec_default_get_buffer2)) {
??????? while (p->state != STATE_SETUP_FINISHED && p->state != STATE_INPUT_READY) {
??????????? pthread_mutex_lock(&p->progress_mutex);
??????????? while (p->state == STATE_SETTING_UP)
??????????????? pthread_cond_wait(&p->progress_cond, &p->progress_mutex);

??????????? if (p->state == STATE_GET_BUFFER) {
??????????????? p->result = ff_get_buffer(p->avctx, p->requested_frame, p->requested_flags);
??????????????? p->state? = STATE_SETTING_UP;
??????????????? pthread_cond_signal(&p->progress_cond);
??????????? }
??????????? pthread_mutex_unlock(&p->progress_mutex);
??????? }
??? }

??? fctx->prev_thread = p;
??? fctx->next_decoding++;

??? return 0;

}

主線程接收數據,準備完畢后發出pthread_cond_signal(&p->input_cond)信號,然后解碼線程接收到以后,設置線程狀態為finish_setup,發送廣播p->process_cond,進行解碼,

解碼線程解完以后,發送p->progress_cond信號,主線程回調,從解碼線程中獲取get_buffer,解碼之后的數據,然后發送p->progress_cond信號給解碼線程,然后解碼線程發出p->output_cond信號給主線程,主線程輸出解碼之后的frame給用戶


注釋1:




總結

以上是生活随笔為你收集整理的FFmepg 多线程解码历程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

在线中文字幕播放 | 在线观看视频福利 | 99热超碰在线 | 五月香视频在线观看 | 欧美怡红院视频 | 国产精品岛国久久久久久久久红粉 | 久久久久久高潮国产精品视 | 国产 日韩 欧美 在线 | 丝袜护士aⅴ在线白丝护士 天天综合精品 | 久久久999免费视频 日韩网站在线 | 99久久婷婷国产精品综合 | 免费在线观看一级片 | 婷色| 色综合久久悠悠 | 国产在线一卡 | 久久免费公开视频 | 手机在线看片日韩 | 日韩成人不卡 | 夜添久久精品亚洲国产精品 | 大荫蒂欧美视频另类xxxx | 国产精品一区在线观看你懂的 | 夜夜躁日日躁狠狠久久av | av日韩av| 日韩三级.com | 久久久高清免费视频 | 久久婷婷激情 | 国产色啪| 成人av高清 | 丁香六月欧美 | 欧美激情h| 亚洲五月 | 人人爱天天操 | 99免费看片| 天天躁日日躁狠狠躁av麻豆 | 亚洲成色777777在线观看影院 | 国产aaa大片| 久久国产精品久久久 | 日韩中文免费视频 | 午夜视频色 | 久久精品中文字幕免费mv | 国产精品久久 | 中文字幕第一页在线视频 | 亚洲天堂网视频在线观看 | 超碰精品在线 | 又黄又爽又刺激的视频 | 日韩专区一区二区 | 看av免费| 十八岁以下禁止观看的1000个网站 | 久草视频免费观 | 国产综合激情 | 中文字幕.av.在线 | 草久在线观看 | 久久一线 | 日韩欧美99 | 四虎成人精品在永久免费 | 亚洲免费一级电影 | 九九色在线观看 | 91九色视频 | 天天干夜夜夜 | 美女视频永久黄网站免费观看国产 | 精品久久久久久一区二区里番 | 久草在线高清视频 | 亚洲国产精品久久久久久 | 欧美一级黄色视屏 | 免费看污污视频的网站 | 天天色播 | 国产成人精品免费在线观看 | 日韩欧美精品一区 | 成人a毛片 | 波多野结衣电影一区二区三区 | 国产日产精品一区二区三区四区的观看方式 | 免费在线黄色av | 伊人天堂网 | 欧美 日韩 成人 | 久久久久综合精品福利啪啪 | 日韩欧美xxxx | 成人国产精品 | 欧美精品一区二区三区一线天视频 | 成人av一区二区兰花在线播放 | 白丝av在线 | 欧美一级免费 | 欧美不卡在线 | 欧美天天射 | 国产精品成人免费精品自在线观看 | 日本久久久亚洲精品 | 亚洲视频免费在线看 | 91 中文字幕 | 国产在线a免费观看 | 狠狠干我 | 99在线观看视频网站 | 国产aaa毛片 | 久草观看视频 | 天堂在线一区二区三区 | 99久久精品免费看国产麻豆 | 黄色片网站av | 91精品毛片 | 亚洲色图激情文学 | 91精品国产一区二区在线观看 | 精品国产1区2区 | 最近字幕在线观看第一季 | 久久免费高清视频 | 国内视频1区 | 国产精品密入口果冻 | 看国产黄色片 | 国产视频欧美视频 | 97视频在线免费 | 久久久久国产精品一区二区 | 天天综合亚洲 | 激情丁香5月 | 91 在线视频 | 啪一啪在线 | 中文字幕 二区 | 日韩在线观看精品 | 久久婷婷丁香 | 国产精品一区二区免费看 | 国精产品999国精产品视频 | 久久久精品欧美 | 国产精品网站一区二区三区 | 免费看成人片 | 九色精品在线 | 国产在线p | 国产片网站 | 伊人狠狠干| 久久精品久久国产 | 久久久人 | 在线亚洲午夜片av大片 | 国产精品9区 | 午夜.dj高清免费观看视频 | 五月天综合网站 | www久| 超碰免费公开 | 国产乱码精品一区二区三区介绍 | 日精品| 亚洲欧美国产精品 | 毛片精品免费在线观看 | 成人av影视观看 | 亚洲精品自拍视频在线观看 | 久久综合精品国产一区二区三区 | 黄色av免费电影 | 美女激情影院 | 911久久香蕉国产线看观看 | 久久综合天天 | 欧美激情视频三区 | 免费在线观看av网址 | 国产免费嫩草影院 | 婷婷激情欧美 | 黄色免费高清视频 | 麻豆一二| 丰满少妇对白在线偷拍 | 成人av网站在线观看 | 中文字幕在线电影 | 免费亚洲视频 | 国产精品久久久久久久毛片 | 精品一区二区三区香蕉蜜桃 | 91自拍视频在线观看 | 久久久久亚洲精品中文字幕 | 久久国产一区 | 一本色道久久综合亚洲二区三区 | 免费看短 | 午夜av免费观看 | 亚洲精品自在在线观看 | 人人澡视频 | 国产精品久久久久久久久久久久冷 | 国产成人福利在线 | 国产一卡在线 | 欧美日韩在线电影 | 午夜视频在线瓜伦 | www.超碰| 国产护士在线 | 亚洲精品免费在线视频 | 日韩av成人| 久久艹国产 | 97超碰在线资源 | 中文在线中文a | 亚洲精品午夜久久久久久久久久久 | 五月婷婷激情六月 | 色婷在线 | 天天爽夜夜爽人人爽一区二区 | 免费网站看v片在线a | 亚洲国产69| 国产精久久久久久妇女av | 欧美va日韩va | 精品国产区在线 | 97超碰.com | 色操插 | 日本不卡一区二区三区在线观看 | 国产精品久久久久久吹潮天美传媒 | 在线免费日韩 | 久草成人在线 | 国产小视频网站 | 永久av免费在线观看 | 欧美国产大片 | 亚洲蜜桃在线 | 黄色网址中文字幕 | 丁香视频在线观看 | 激情久久久久久久久久久久久久久久 | 国际精品久久 | 久久精品国产精品亚洲 | 另类老妇性bbwbbw高清 | 天天爽夜夜爽人人爽一区二区 | 久久久久久久久久久网 | 国产精品精品国产色婷婷 | 日本公妇色中文字幕 | 一本一本久久a久久精品牛牛影视 | 在线看不卡av | 国产成人av电影在线观看 | 日韩午夜电影 | 免费看污黄网站 | 午夜999| 99色网站| av网站有哪些 | 国产亚洲日 | 91久久久久久久一区二区 | 亚洲区另类春色综合小说 | 欧美国产大片 | 91 在线视频 | 99久久精品国产毛片 | 麻豆视频免费入口 | 久久99久久99精品免视看婷婷 | 色鬼综合网 | a天堂中文在线 | 国产精品久久久久久久免费观看 | 日韩毛片在线播放 | 亚洲国产一区在线观看 | 亚洲免费av片 | 91久久国产露脸精品国产闺蜜 | 韩国av免费在线 | 日日操日日插 | 亚洲精品毛片一级91精品 | 国产资源网| 波多野结衣综合网 | 一区二区三区四区久久 | 亚洲 欧美日韩 国产 中文 | 视频在线观看入口黄最新永久免费国产 | 欧美婷婷色 | 欧美一区二视频在线免费观看 | av成人免费在线 | 久草com | 国产免费视频一区二区裸体 | 毛片无卡免费无播放器 | 国产高清视频免费观看 | 亚洲黄色大片 | 国产日韩视频在线观看 | 亚洲精品视频在线观看免费视频 | 一级做a爱片性色毛片www | 久久福利 | 免费黄色网址网站 | 国产成人精品午夜在线播放 | 手机看片国产 | 免费在线国产视频 | 国外成人在线视频网站 | 国产精品久久久久久久久久久久午夜 | 欧美另类调教 | 毛片基地黄久久久久久天堂 | av高清一区二区三区 | 天天综合网天天 | 亚洲免费一级 | 日本夜夜草视频网站 | 亚洲欧美日韩精品久久奇米一区 | 久久久久综合网 | 欧美精品一区在线发布 | 成人网页在线免费观看 | 97色视频在线 | h视频在线看| 最新一区二区三区 | 免费在线观看日韩视频 | 日韩av午夜在线观看 | 狠狠色丁香九九婷婷综合五月 | 草久热 | 五月婷婷一区二区三区 | 亚洲国产一区av | 久久久伊人网 | 色婷婷综合久久久久中文字幕1 | 欧美日韩国产一区二 | 激情视频区 | 9热精品| 成年人免费电影 | 久久久久久久久久久久久久免费看 | 国产精品乱码一区二三区 | 国产精品色视频 | 四虎国产精品成人免费影视 | 亚洲精品av在线 | 99热只有精品在线观看 | 日韩免费一区二区三区 | 国产色妞影院wwwxxx | 国产在线观看免费 | 欧美片网站yy | 麻豆国产网站入口 | 国产精品18久久久久久久网站 | 韩日精品中文字幕 | 国产精品久久久久久久久久久杏吧 | 一区二区三区高清 | 欧美日韩中文字幕综合视频 | 欧美国产精品一区二区 | 色综合网 | 久久免费视频在线观看 | av日韩av| 久草资源在线观看 | 久久精品5| av成人动漫 | 欧美精品在线观看一区 | 人人插人人射 | 免费观看国产精品 | 国产一区二区不卡视频 | 免费看黄的| 亚洲视频播放 | 国产成人在线免费观看 | 最近2019年日本中文免费字幕 | 国产精品美女久久久免费 | 国产一级高清 | 久久久国产毛片 | 国产色就色 | 国产综合视频在线观看 | 免费高清看电视网站 | 日韩久久午夜一级啪啪 | 国内精品久久久久久久久久清纯 | 麻豆国产电影 | 亚洲免费观看视频 | 五月婷婷久草 | 国产精品精品久久久久久 | 91亚洲激情 | 国产精品入口麻豆www | 国产麻豆精品传媒av国产下载 | 91麻豆精品国产91久久久更新时间 | 少妇按摩av | 欧美乱熟臀69xxxxxx | 免费福利视频导航 | 亚洲午夜精 | 免费看的国产视频网站 | 亚洲国产精久久久久久久 | 日韩国产欧美在线视频 | 国产韩国日本高清视频 | 日日骑 | 久久精品国产亚洲精品2020 | 久爱综合 | www.天天干.com | 人人干天天射 | 精品一区二区久久久久久久网站 | 国产中文字幕在线看 | 午夜成人影视 | 黄色资源网站 | 亚洲理论在线观看 | 99午夜 | 欧美一区中文字幕 | 亚洲精品一区二区三区新线路 | 黄色毛片电影 | 中文字幕在线观看免费 | www视频在线免费观看 | 久久看片 | 欧美日韩一区三区 | 精品九九九九 | 国产精品一区久久久久 | 久久久久影视 | 亚洲国产97在线精品一区 | 在线视频 一区二区 | 国产精品18久久久久久首页狼 | 狠狠狠色丁香婷婷综合久久五月 | 中文字幕免费在线看 | 国产精品12345 | 国产精品自在线 | 欧美精品亚洲精品 | 久久婷婷久久 | 日韩系列 | 激情丁香久久 | 国产在线久草 | 成人av午夜 | 夜夜夜精品 | 69人人| 免费观看的黄色片 | 久久久久久欧美二区电影网 | 免费观看性生交大片3 | www.日日日.com | 西西444www大胆无视频 | 久久久久久久久久久久久9999 | 日韩欧美一区二区三区在线 | 91精品麻豆| 国产视频一区二区在线播放 | 成人在线一区二区三区 | 国产成人三级在线观看 | 免费日韩一区二区三区 | 在线播放91 | 日本爱爱片 | 国产精品久久久久久久久久白浆 | 午夜免费在线观看 | 9久久精品 | www.com黄 | 在线观看免费中文字幕 | 特级黄色视频毛片 | 日本黄色大片免费 | a在线观看国产 | 在线观看一级视频 | 久久国产精品精品国产色婷婷 | 91 在线视频 | 少妇bbw搡bbbb搡bbbb| 天天干,天天射,天天操,天天摸 | 国产一区影院 | 91精品一区在线观看 | 91插插插免费视频 | 91三级视频 | 亚洲乱码精品 | 久久女同性恋中文字幕 | 国产高清av免费在线观看 | 国产精品不卡在线播放 | 日本一区二区三区免费看 | 天天拍夜夜拍 | 青青河边草免费直播 | 99久久电影 | 在线视频日韩一区 | 久久久久久久久久亚洲精品 | 99视频在线免费看 | 九九在线视频免费观看 | 在线欧美最极品的av | 免费亚洲一区二区 | 久久精品国产免费观看 | 黄色一级在线免费观看 | 国产精品手机视频 | 亚洲国产成人精品电影在线观看 | 国产亚洲一区二区三区 | 日本精品va在线观看 | a资源在线 | 三级在线视频观看 | 国产精品久久久久久久久久妇女 | 最近高清中文字幕 | 国产精品资源在线观看 | 在线а√天堂中文官网 | 国产黄a三级三级三级三级三级 | 国产超碰在线观看 | 亚洲精品美女在线观看播放 | 色视频在线观看 | 97在线精品 | 啪啪免费视频网站 | 欧美精品久久久 | 在线视频日韩欧美 | 久久久www | www.五月天激情 | 天天色综合1| 久综合网 | 蜜桃视频日本 | 4hu视频 | 国产精品午夜久久 | 9在线观看免费高清完整 | 手机在线看片日韩 | 国产精品12345 | 成人黄色影片在线 | 亚洲黄色a| 国产精品一区二区久久精品 | 国产精品成人久久久 | 久久伦理视频 | 中文国产成人精品久久一 | 欧美久久久久久久 | 天天操 夜夜操 | 97超碰网| 天天射色综合 | 叶爱av在线 | 欧美成人xxxxx | 中文字幕在线免费观看视频 | 日韩精品在线观看视频 | 日韩精品亚洲专区在线观看 | 日韩高清一区 | 99婷婷狠狠成为人免费视频 | 麻豆久久一区二区 | 久久深夜福利免费观看 | 狠狠五月婷婷 | 97视频人人澡人人爽 | 国产欧美精品在线观看 | 久久在线| 探花视频在线版播放免费观看 | 天天插日日插 | 欧美综合在线视频 | 国产丝袜| 日韩av电影一区 | 97超碰在线资源 | 综合色在线| 人人操日日干 | 人人揉人人揉人人揉人人揉97 | 99在线免费视频 | 日韩国产精品一区 | 91看片在线| 亚洲一区 av | 一区二区三区免费在线观看 | 在线欧美最极品的av | 久久综合免费视频 | 日韩精品中文字幕久久臀 | 国产 一区二区三区 在线 | 国产成人久久精品亚洲 | 精品在线视频一区 | 国内精品福利视频 | 国产精品成人一区二区三区 | 99久久久国产免费 | 久久神马影院 | 国产一区欧美一区 | 久久夜夜夜 | 偷拍久久久 | 精品视频免费播放 | 天天色综合1 | 国产一区二区高清不卡 | 婷婷在线色 | 国产精品久久久久久久av大片 | 免费在线国产精品 | 园产精品久久久久久久7电影 | 久久精品国产免费看久久精品 | 黄色片毛片 | 日韩高清二区 | 久久综合五月婷婷 | 久久久国产99久久国产一 | 精品91视频 | 欧美日韩免费视频 | 深爱婷婷网| 久草爱| 亚洲成人av电影 | 国产97在线视频 | 成人黄色片在线播放 | 最新国产视频 | 日韩av在线资源 | 亚洲aⅴ一区二区三区 | 久久人人爽人人爽人人片av软件 | 久久久久久久久久网 | 成片人卡1卡2卡3手机免费看 | 国产一区二区三区在线免费观看 | 天天操天天操天天操 | 欧美不卡视频在线 | 国产亚洲精品久久久久久电影 | 色婷婷成人 | 免费在线播放视频 | av在线免费在线 | 国产精品 日本 | 91秒拍国产福利一区 | 在线 影视 一区 | 一级黄色在线免费观看 | 成人av免费在线播放 | 色中色资源站 | 色在线视频 | 韩国一区二区av | 99精品视频免费在线观看 | 一本一道久久a久久综合蜜桃 | 正在播放一区二区 | 91精品啪在线观看国产 | 五月天天在线 | 91超碰免费在线 | 亚洲精选久久 | 夜夜夜夜夜夜操 | 久久国产精品久久w女人spa | 日韩sese| 日韩电影在线观看一区二区 | 国产第一页福利影院 | 欧美国产精品一区二区 | 三级av黄色| 麻豆首页| 九九综合九九综合 | 在线不卡a | 中文字幕亚洲在线观看 | 很黄很污的视频网站 | 亚洲成人影音 | 国产精品你懂的在线观看 | 久久综合久久综合九色 | 国产在线欧美在线 | 特级黄色一级 | 国内一区二区视频 | 天天狠狠操 | 国产成人精品亚洲日本在线观看 | 99热在 | 999久久久欧美日韩黑人 | 日韩在线观看你懂得 | 日韩激情精品 | 日本精品一 | 国产日韩精品一区二区 | 精品视频资源站 | 国产麻豆精品久久一二三 | 天天干天天干天天干天天干天天干天天干 | 黄色av电影在线 | 人人舔人人射 | 一区二区三区日韩在线 | 国产精品18久久久久久vr | 99热在线观看 | 日韩免费观看高清 | 99精品久久99久久久久 | 激情久久伊人 | 国产看片网站 | 国产三级在线播放 | 亚洲精品中文字幕在线观看 | 国产精品密入口果冻 | 丁香花在线视频观看免费 | 日韩免费高清在线观看 | 免费观看日韩av | 色a资源在线 | 久久精品一二三 | 99re6热在线精品视频 | 一本一本久久a久久 | 中文字幕在线看片 | 一二三区av | 97夜夜澡人人双人人人喊 | 久久一区精品 | 日本中文字幕一二区观 | 亚洲一级黄色av | 国产精品久久久影视 | 国产高清在线免费视频 | 免费a级观看 | av电影在线免费 | 丁香综合 | 国产中文字幕在线视频 | 国产91综合一区在线观看 | 中文字幕二区三区 | 久久精品国产美女 | 91精品国产自产在线观看永久 | 久久午夜影视 | 日韩成人免费在线电影 | 日韩美在线| 久久成人精品电影 | 亚洲精品乱码久久久久久按摩 | 成人免费大片黄在线播放 | 久影院| 国产精品白浆 | 国产精品久久久久久久久久久免费 | 精品xxx | 东方av免费在线观看 | 国产在线p | 久久国产精彩视频 | 国产精品自产拍在线观看蜜 | av成人在线观看 | 99热官网| 激情中文字幕 | 国产精品第一页在线观看 | 国产一区二区三区免费观看视频 | 亚洲九九爱 | 日韩成人精品一区二区 | 国产99久久| 91中文在线视频 | 99色亚洲 | 亚洲精品视频免费观看 | 亚洲精品理论片 | 免费看片亚洲 | 中文视频在线播放 | 国产色区| 久久国产精品区 | 91在线亚洲 | 五月开心综合 | 国产一级久久久 | 日本中文字幕高清 | 蜜桃视频在线视频 | 99r在线 | 天天鲁天天干天天射 | 婷婷丁香在线视频 | 成人网页在线免费观看 | 97在线观看视频 | 日日躁你夜夜躁你av蜜 | 国模一区二区三区四区 | 日韩激情精品 | 久 久久影院 | 精品一区二区在线免费观看 | 肉色欧美久久久久久久免费看 | 在线观看的黄色 | 国产精品短视频 | 99久精品视频 | 一级c片| 日韩系列在线 | 黄色免费大片 | 日本女人在线观看 | 亚洲影视九九影院在线观看 | 精品91在线 | 九色福利视频 | 97人人看| 午夜 久久 tv | 超碰在线公开免费 | 国产女人免费看a级丨片 | 91精品国产一区二区三区 | 日韩精品免费 | 黄色影院在线免费观看 | 欧美精品中文字幕亚洲专区 | 高清在线一区二区 | 四虎最新入口 | 国产91大片 | 久久视频中文字幕 | 91免费观看视频网站 | 国产精品久久一区二区无卡 | 在线视频黄 | 日韩精品视频在线观看网址 | 日日夜夜精品免费视频 | 成人免费一区二区三区在线观看 | 中文字幕av播放 | 超碰日韩 | 亚洲精品乱码久久久久久久久久 | 亚洲精品动漫在线 | 日韩高清dvd| 亚洲女人av | 色欲综合视频天天天 | 人人模人人爽 | 中文字幕一区二区三区乱码不卡 | 亚洲欧美综合精品久久成人 | 最新av免费在线观看 | 欧美日韩一级久久久久久免费看 | 国产日韩欧美在线一区 | 亚洲精品视频在线播放 | 97在线视频网站 | 国产精品2区| 亚洲3级| 国内视频在线观看 | 激情丁香5月 | 免费三级在线 | 97韩国电影 | 97在线观看视频免费 | a一片一级 | 91大片网站 | 精品国产成人av在线免 | 日韩精品最新在线观看 | 国产精品永久在线观看 | 香蕉日日 | 毛片a级片| 最新av免费在线观看 | 久久嗨| 国产久草在线 | 国产呻吟在线 | 手机看片国产日韩 | 色妞久久福利网 | 六月色丁| 亚洲婷婷丁香 | 日韩欧美视频免费看 | 91理论电影 | 国产视 | 欧美精品在线观看免费 | 三级在线国产 | 久久国产精品99久久人人澡 | 免费无遮挡动漫网站 | 久草免费在线观看视频 | 欧美一区在线观看视频 | 国产在线观看免费观看 | 中文字幕在线观看播放 | 97久久精品午夜一区二区 | 97超碰.com| 国产麻豆果冻传媒在线观看 | 精品免费国产一区二区三区四区 | 亚洲精品黄色 | 乱男乱女www7788 | 天天爽天天碰狠狠添 | 国产精品一区二区av影院萌芽 | 国产小视频在线免费观看 | 国产精品视频地址 | 日韩亚洲国产精品 | 99久久电影 | 久久亚洲私人国产精品va | 亚洲一区二区精品 | 91精彩在线视频 | 香蕉视频国产在线 | 天天曰天天曰 | 黄色大片免费播放 | 国产精品成人久久 | 国产一区二区高清 | 中文字幕在线看片 | 91色蜜桃| 超碰大片 | 国产精品一区免费看8c0m | 9i看片成人免费看片 | 久久伦理电影 | 日韩深夜在线观看 | 亚洲精品美女久久久 | 91禁在线看 | 毛片一级免费一级 | 网站在线观看日韩 | 欧美精品999 | 国产vs久久 | 国产精品美女久久久久久久久 | 国产精品毛片一区二区三区 | 91人人爱 | 国产无套精品久久久久久 | 97成人资源 | 成人午夜片av在线看 | 久久久影院一区二区三区 | 日韩免费福利 | 亚洲精品视频免费看 | 日韩欧美精品在线观看视频 | 国产午夜免费视频 | 亚洲在线看 | 丝袜美腿在线播放 | 久久国产影视 | 天天综合网久久综合网 | 午夜精品一区二区三区在线播放 | 九精品| 日韩精品一区二区三区水蜜桃 | 久久精品中文字幕免费mv | 国产不卡免费 | 一区二区视频在线观看免费 | 天天插天天狠天天透 | 久久久久久毛片精品免费不卡 | 在线欧美最极品的av | 久久久99精品免费观看乱色 | 欧美另类高清 | 亚洲精品动漫久久久久 | 五月婷婷丁香六月 | 欧美一级片在线 | 色综合天天综合 | 精品久久久久久久久久久久 | 人人盈棋牌 | 亚洲丝袜一区 | 日本高清xxxx | 久久综合九色综合久久久精品综合 | 久久一二三四 | 精品国产精品久久 | 东方av在线免费观看 | 国偷自产中文字幕亚洲手机在线 | 狠狠五月天 | 精品久久久久久久久久国产 | 丁香六月在线观看 | 日韩欧美视频一区二区三区 | 成片免费观看视频 | 夜夜爽88888免费视频4848 | 日本在线观看一区二区 | 综合久久久久久久 | a黄色一级 | 日韩精品一区二区免费 | 黄色成人91 | 亚洲国产精品一区二区久久,亚洲午夜 | 国产黄色一级大片 | 婷婷精品视频 | 亚洲精品合集 | 激情综合网色播五月 | 国产精品久久久久久久久久99 | 欧美日本高清视频 | 免费成人在线视频网站 | 久草久草在线 | 摸bbb搡bbb搡bbbb | 欧美日韩一级久久久久久免费看 | 97精品国产一二三产区 | 美女久久久久久久久久 | 国产亚洲一区二区在线观看 | 久草资源免费 | 97超碰免费在线 | 亚洲91网站| 手机av资源 | 人人澡超碰碰97碰碰碰软件 | 999热视频| 日韩四虎| 在线日本看片免费人成视久网 | 国产精品1区2区3区 久久免费视频7 | 亚洲蜜桃av | 午夜精品视频一区二区三区在线看 | 欧美孕妇视频 | 精品国产伦一区二区三区观看体验 | www.日日日.com| 五月婷婷导航 | 成人黄色在线 | 99久久精品午夜一区二区小说 | 国产中年夫妇高潮精品视频 | www.天天操 | 久久成人视屏 | 99精品视频在线播放免费 | 国产一二区免费视频 | 狠狠五月婷婷 | 玖玖视频精品 | 天天干天天摸天天操 | 亚洲理论电影网 | 在线免费观看欧美日韩 | 亚洲综合在线观看视频 | 国产乱码精品一区二区三区介绍 | 中文字幕资源在线观看 | 色综合久久久久网 | 中文字幕国产一区二区 | 精品99久久久久久 | 丁香五婷 | 91免费在线 | 精品主播网红福利资源观看 | 国产黄色片免费观看 | 国产午夜精品一区二区三区四区 | 夜夜爽www| 国产精品久久久视频 | 中文字幕大全 | 欧美日韩久久 | 国产在线欧美日韩 | 9在线观看免费高清完整版 玖玖爱免费视频 | 亚洲精品乱码久久久久久写真 | 亚洲一区二区精品3399 | 日韩av成人在线观看 | 免费成人结看片 | 欧美成人h版在线观看 | 香蕉视频网址 | 91av看片| 在线高清一区 | 97国产超碰在线 | 日日婷婷夜日日天干 | 99中文视频在线 | 亚洲精品字幕在线 | 久久99影院| 中文字幕人成乱码在线观看 | 精品国产三级a∨在线欧美 免费一级片在线观看 | 99色人 | 欧美激情精品久久久久 | 亚洲成人高清在线 | 91av视频网站 | 成av在线 | 在线免费观看麻豆 | 国产黄色精品在线 | 91中文字幕网 | 亚洲国产偷 | 人人舔人人插 | 高清一区二区 | 丁香六月激情 | www.夜夜爱 | 国产区第一页 | 国产精品九色 | 国产精品黄色 | 国产在线观看国语版免费 | 久草视频99 | 国产亚洲精品免费 | 国产福利免费看 | 日本午夜在线观看 | 色噜噜狠狠狠狠色综合 | 97国产精品一区二区 | 91亚洲精品在线 | 久久99久久99精品免费看小说 | www.久艹| 亚洲精品成人av在线 | 久久99免费 | 久久久久久久久久久久久久电影 | 一 级 黄 色 片免费看的 | 91精品国产综合久久福利不卡 | 国产精品久久99 | 婷婷狠狠操| 97国产一区 | 成人一级免费视频 | 超碰午夜 | 深爱婷婷久久综合 | 国产视频精品免费播放 | 一区三区视频在线观看 | 中文字幕免费观看全部电影 | 国产剧情一区二区在线观看 | 欧美性极品xxxx做受 | 黄色毛片在线看 | 久久6精品 | 一本一道久久a久久精品蜜桃 | 亚洲成a人片77777kkkk1在线观看 | 精品久久网站 | 精品在线亚洲视频 | 成人羞羞视频在线观看免费 | 98福利在线 | 麻豆你懂的 | 国产青青青 | 日本xxxxav| 91传媒视频在线观看 | 亚洲精品在线一区二区三区 | 国产精品毛片 | 亚洲成人av一区 | 国产综合视频在线观看 | 99久久精品久久久久久清纯 | 蜜桃视频在线观看一区 | 日韩字幕 | 91成人精品一区在线播放69 | 亚洲国产精品第一区二区 | 黄色一集片 | 国偷自产中文字幕亚洲手机在线 | 五月婷婷一级片 | 日躁夜躁狠狠躁2001 | 欧美大片在线观看一区 | 韩国三级在线一区 | 国产色在线,com | 日韩黄色在线观看 | 久久综合五月天 | 九九免费在线视频 | 99久久综合国产精品二区 | 一区二区三区电影大全 | 久草9视频 | 日韩精品中文字幕一区二区 | 国产一区在线免费观看 | 97偷拍在线视频 | 欧美一二三区在线观看 | 欧美在线不卡一区 | 中文字幕在线视频网站 | 成人网在线免费视频 | 国产精品一区二区久久精品爱微奶 | 91精品蜜桃 | 国产精品成人aaaaa网站 | 日韩欧美xxxx | 欧美日韩午夜爽爽 | 亚洲日本va中文字幕 | 亚洲一级黄色片 | 狠狠色丁香九九婷婷综合五月 | 国内丰满少妇猛烈精品播放 | 中文字幕中文字幕在线中文字幕三区 | 最近中文字幕视频网 | 99自拍视频在线观看 | 久久国产精品影片 | 日韩精品一区二区三区在线视频 | 9在线观看免费 | 国产成人香蕉 | 精品一二三四在线 | 日韩在线欧美在线 | 欧美成人91 | 亚洲欧美综合 | 一区二区免费不卡在线 | 色多多污污| 808电影 | 久久午夜电影院 | 亚洲成人精品国产 | 免费av看片 | 美女视频黄网站 | 成人99免费视频 | 欧美a性| 狠狠躁夜夜躁人人爽超碰97香蕉 | 97天堂网| 亚洲精品国产精品国自产观看浪潮 | 国产精品99免费看 |