Exemple #1
0
static void decode(struct sd *sd, struct demux_packet *packet)
{
    struct sd_lavc_priv *priv = sd->priv;
    AVCodecContext *avctx = priv->avctx;
    double ts = av_q2d(av_inv_q(avctx->time_base));
    AVSubtitle sub = {0};
    AVPacket pkt;
    int ret, got_sub;

    mp_set_av_packet(&pkt, packet);
    pkt.pts = packet->pts == MP_NOPTS_VALUE ? AV_NOPTS_VALUE : packet->pts * ts;
    pkt.duration = packet->duration * ts;

    ret = avcodec_decode_subtitle2(avctx, &sub, &got_sub, &pkt);
    if (ret < 0) {
        mp_msg(MSGT_OSD, MSGL_ERR, "Error decoding subtitle\n");
    } else if (got_sub) {
        for (int i = 0; i < sub.num_rects; i++) {
            char *ass_line = sub.rects[i]->ass;
            if (!ass_line)
                break;
            // This might contain embedded timestamps, using the "old" ffmpeg
            // ASS packet format, in which case pts/duration might be ignored
            // at a later point.
            sd_conv_add_packet(sd, ass_line, strlen(ass_line),
                               packet->pts, packet->duration);
        }
    }

    avsubtitle_free(&sub);
}
void CDVDOverlayCodecFFmpeg::Flush()
{
  avsubtitle_free(&m_Subtitle);
  m_SubtitleIndex = -1;

  avcodec_flush_buffers(m_pCodecContext);
}
void dvbsub_ass_clear(void)
{
	OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(ass_mutex);

	while(ass_queue.size()) {
		ass_data *a = (ass_data *) ass_queue.pop();
		if (a) {
			avsubtitle_free(&a->sub);
			delete a;
		}
	}
	while(!sem_trywait(&ass_sem));

	ass_track = NULL;
	for(std::map<int,ASS_Track*>::iterator it = ass_map.begin(); it != ass_map.end(); ++it)
		ass_free_track(it->second);
	ass_map.clear();
	if (ass_renderer) {
		ass_renderer_done(ass_renderer);
		ass_renderer = NULL;
	}
	if (ass_library) {
		ass_library_done(ass_library);
		ass_library = NULL;
	}
	clear_queue();
}
void dvbsub_ass_write(AVCodecContext *c, AVSubtitle *sub, int pid)
{
	if (ass_reader_running) {
		ass_queue.push((uint8_t *)new ass_data(c, sub, pid));
		sem_post(&ass_sem);
		memset(sub, 0, sizeof(AVSubtitle));
	} else
		avsubtitle_free(sub);
}
Exemple #5
0
static void clear_sub(struct sub *sub)
{
    sub->count = 0;
    sub->pts = MP_NOPTS_VALUE;
    sub->endpts = MP_NOPTS_VALUE;
    if (sub->valid)
        avsubtitle_free(&sub->avsub);
    sub->valid = false;
}
static int subtitle_handler(AVCodecContext *avctx, void *frame,
                            int *got_sub_ptr, AVPacket *avpkt)
{
    AVSubtitle sub;
    int ret = avcodec_decode_subtitle2(avctx, &sub, got_sub_ptr, avpkt);
    if (ret >= 0 && *got_sub_ptr)
        avsubtitle_free(&sub);
    return ret;
}
int CDVDOverlayCodecFFmpeg::Decode(DemuxPacket *pPacket)
{
  if (!m_pCodecContext || !pPacket)
    return 1;

  int gotsub = 0, len = 0;

  avsubtitle_free(&m_Subtitle);

  AVPacket avpkt;
  av_init_packet(&avpkt);
  avpkt.data = pPacket->pData;
  avpkt.size = pPacket->iSize;
  avpkt.pts = pPacket->pts == DVD_NOPTS_VALUE ? AV_NOPTS_VALUE : (int64_t)pPacket->pts;
  avpkt.dts = pPacket->dts == DVD_NOPTS_VALUE ? AV_NOPTS_VALUE : (int64_t)pPacket->dts;

  len = avcodec_decode_subtitle2(m_pCodecContext, &m_Subtitle, &gotsub, &avpkt);

  if (len < 0)
  {
    CLog::Log(LOGERROR, "%s - avcodec_decode_subtitle returned failure", __FUNCTION__);
    Flush();
    return OC_ERROR;
  }

  if (len != avpkt.size)
    CLog::Log(LOGWARNING, "%s - avcodec_decode_subtitle didn't consume the full packet", __FUNCTION__);

  if (!gotsub)
    return OC_BUFFER;

  double pts_offset = 0.0;
 
  if (m_pCodecContext->codec_id == AV_CODEC_ID_HDMV_PGS_SUBTITLE && m_Subtitle.format == 0)
  {
    // for pgs subtitles the packet pts of the end_segments are wrong
    // instead use the subtitle pts to calc the offset here
    // see http://git.videolan.org/?p=ffmpeg.git;a=commit;h=2939e258f9d1fff89b3b68536beb931b54611585

    if (m_Subtitle.pts != AV_NOPTS_VALUE && pPacket->pts != DVD_NOPTS_VALUE)
    {
      pts_offset = m_Subtitle.pts - pPacket->pts ;
    }
  }

  m_StartTime   = DVD_MSEC_TO_TIME(m_Subtitle.start_display_time);
  m_StopTime    = DVD_MSEC_TO_TIME(m_Subtitle.end_display_time);

  //adapt start and stop time to our packet pts
  bool dummy = false;
  CDVDOverlayCodec::GetAbsoluteTimes(m_StartTime, m_StopTime, pPacket, dummy, pts_offset);
  m_SubtitleIndex = 0;

  return OC_OVERLAY;
}
Exemple #8
0
static void decode(struct sd *sd, struct demux_packet *packet)
{
    struct sd_lavc_priv *priv = sd->priv;
    AVCodecContext *avctx = priv->avctx;
    AVSubtitle sub = {0};
    AVPacket pkt;
    AVPacket parsed_pkt = {0};
    int ret, got_sub;

    mp_set_av_packet(&pkt, packet, &avctx->time_base);

    if (sd->codec && strcmp(sd->codec, "webvtt-webm") == 0) {
        if (parse_webvtt(&pkt, &parsed_pkt) < 0) {
            MP_ERR(sd, "Error parsing subtitle\n");
            goto done;
        }
        pkt = parsed_pkt;
    }

    ret = avcodec_decode_subtitle2(avctx, &sub, &got_sub, &pkt);
    if (ret < 0) {
        MP_ERR(sd, "Error decoding subtitle\n");
    } else if (got_sub) {
        for (int i = 0; i < sub.num_rects; i++) {
            char *ass_line = sub.rects[i]->ass;
            if (!ass_line)
                break;
            // This might contain embedded timestamps, using the "old" ffmpeg
            // ASS packet format, in which case pts/duration might be ignored
            // at a later point.
            sd_conv_add_packet(sd, ass_line, strlen(ass_line),
                               packet->pts, packet->duration);
        }
    }

done:
    avsubtitle_free(&sub);
    av_free_packet(&parsed_pkt);
}
void plex_link_subtitles_to_graph(AVFilterGraph* g)
{
#if CONFIG_INLINEASS_FILTER
    int contextId = 0;
    for (int i = 0; i < nb_filtergraphs && contextId < plexContext.nb_inlineass_ctxs; i++) {
        AVFilterGraph* graph = filtergraphs[i]->graph;
        if (!graph)
            continue;
        for (int i = 0; i < graph->nb_filters && contextId < plexContext.nb_inlineass_ctxs; i++) {
            const AVFilterContext* filterCtx = graph->filters[i];
            if (strcmp(filterCtx->filter->name, "inlineass") == 0) {
                AVFilterContext *ctx = graph->filters[i];
                InlineAssContext *assCtx = &plexContext.inlineass_ctxs[contextId++];
                assCtx->ctx = ctx;

                for (int j = 0; j < nb_input_streams; j++) {
                    InputStream *ist = input_streams[j];
                    if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT)
                        avfilter_inlineass_add_attachment(ctx, ist->st);
                    if (ist->file_index == assCtx->file_index &&
                        ist->st->index == assCtx->stream_index &&
                        ist->sub2video.sub_queue) {
                        while (av_fifo_size(ist->sub2video.sub_queue)) {
                            AVSubtitle tmp;
                            av_fifo_generic_read(ist->sub2video.sub_queue, &tmp, sizeof(tmp), NULL);
                            plex_process_subtitles(ist, &tmp);
                            avsubtitle_free(&tmp);
                        }
                    }
                }

                avfilter_inlineass_set_fonts(ctx);
            }
        }
    }
#endif
}
Exemple #10
0
int _tmain(int argc, _TCHAR* argv[])
{
    ISubtitles* subtitle = NULL;
    if (!ISubtitles::create(&subtitle)) {
		printf("failed to create subtitle instance.\n");
        return 1;
    }
    
#ifdef EMBEDDING_SUBTITLE
	av_register_all();

	avformat_network_init();

	AVFormatContext *fmt_ctx = NULL;
	char *url = LOCAL_FILE;
	int subtitle_stream_idx = -1;
	AVStream* subtitle_stream;
	AVCodecContext* subtitle_dec_ctx;
	AVPacket pkt;
	AVSubtitle sub;
	int got_sub;
	int ret;
	int index = 0;

	/* open input file, and allocate format context */
    if (avformat_open_input(&fmt_ctx, url, NULL, NULL) < 0) {
		LOGE("Could not open source file");
        return 1;
    }

	/* retrieve stream information */
    if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
        LOGE("Could not find stream information\n");
        return 1;
    }

	if (open_codec_context(fmt_ctx, &subtitle_stream_idx, AVMEDIA_TYPE_SUBTITLE) < 0) {
		LOGE("failed to find subttile track");
		return 1;
	}

	subtitle_stream = fmt_ctx->streams[subtitle_stream_idx];
	subtitle_dec_ctx = subtitle_stream->codec;

	/* dump input information to stderr */
	av_dump_format(fmt_ctx, 0, url, 0);

	SubtitleCodecId codec_id;
	if (subtitle_dec_ctx->codec_id == AV_CODEC_ID_ASS ||
		subtitle_dec_ctx->codec_id == AV_CODEC_ID_SSA)
		codec_id = SUBTITLE_CODEC_ID_ASS;
	else
		codec_id = SUBTITLE_CODEC_ID_TEXT;
	ret = subtitle->addEmbeddingSubtitle(codec_id, "chs", "chs", 
		(const char *)subtitle_dec_ctx->extradata, subtitle_dec_ctx->extradata_size);
	if (ret < 0) {
		LOGE("failed to addEmbeddingSubtitle");
		return 1;
	}

	/* initialize packet, set data to NULL, let the demuxer fill it */
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;

    /* read frames from the file */
    while (av_read_frame(fmt_ctx, &pkt) >= 0 && index < 10 ) {
		if (pkt.stream_index == subtitle_stream_idx) {
			AVPacket orig_pkt = pkt;
			do {
				ret = avcodec_decode_subtitle2(subtitle_dec_ctx, &sub, &got_sub, &pkt);
				if (ret < 0) {
					break;
				}
				if (got_sub) {
					LOGI("got subtitle");

					for (int i=0;i<sub.num_rects;i++) {
						if (sub.rects[i]->ass) {
							int64_t start_time ,stop_time;
							AVRational ra;
							ra.num = 1;
							ra.den = AV_TIME_BASE;
							start_time = av_rescale_q(sub.pts + sub.start_display_time * 1000,
									 ra, subtitle_stream->time_base);
							stop_time = av_rescale_q(sub.pts + sub.end_display_time * 1000,
									 ra, subtitle_stream->time_base);
							subtitle->addEmbeddingSubtitleEntity(0, start_time, stop_time - start_time, 
								sub.rects[i]->ass, strlen(sub.rects[i]->ass)); // my_strlen_utf8_c

							index++;
						}
					}
					avsubtitle_free(&sub);
				}
				pkt.data += ret;
				pkt.size -= ret;
			} while (pkt.size > 0);
			av_free_packet(&orig_pkt);
		}
		else {
			av_free_packet(&pkt);
		}
    }

#else
	if (!subtitle->loadSubtitle(SUB_FILE_PATH, false)) {
		printf("failed to load subtitle: %s", SUB_FILE_PATH);
		return 1;
	}
#endif

    STSSegment* segment = NULL;
	char subtitleText[1024] = {0};

	int line = 0;
    while(line < 20 && subtitle->getNextSubtitleSegment(&segment)) {
        int64_t startTime = segment->getStartTime();
        int64_t stopTime = segment->getStopTime();
		segment->getSubtitleText(subtitleText, 1024);
        LOGI("%01d:%02d:%02d.%02d  --> %01d:%02d:%02d.%02d %s",
            int(startTime/1000/3600), int(startTime/1000%3600/60), int(startTime/1000%60), int(startTime%1000)/10,
            int(stopTime/1000/3600), int(stopTime/1000%3600/60), int(stopTime/1000%60), int(stopTime%1000)/10,
			CW2A(CA2W(subtitleText, CP_UTF8)));

		//getchar();
		line++;
    }

    subtitle->close();

	return 0;
}
void CDVDOverlayCodecFFmpeg::Dispose()
{
  avsubtitle_free(&m_Subtitle);
  avcodec_free_context(&m_pCodecContext);
}
Exemple #12
0
/**
 * Decode a subtitle packet via libavcodec.
 * \return < 0 on error, > 0 if further processing is needed
 */
int decode_avsub(struct sh_sub *sh, uint8_t **data, int *size,
                 double *pts, double *endpts)
{
    AVCodecContext *ctx = sh->context;
    enum CodecID cid = CODEC_ID_NONE;
    int new_type = 0;
    int res;
    int got_sub;
    AVSubtitle sub;
    AVPacket pkt;

    switch (sh->type) {
    case 'b':
        cid = CODEC_ID_DVB_SUBTITLE; break;
    case 'p':
        cid = CODEC_ID_HDMV_PGS_SUBTITLE; break;
    case 'x':
        cid = CODEC_ID_XSUB; break;
    }

    av_init_packet(&pkt);
    pkt.data = *data;
    pkt.size = *size;
    pkt.pts = *pts * 1000;
    if (*pts != MP_NOPTS_VALUE && *endpts != MP_NOPTS_VALUE)
        pkt.convergence_duration = (*endpts - *pts) * 1000;
    if (!ctx) {
        AVCodec *sub_codec;
        init_avcodec();
        ctx = avcodec_alloc_context3(NULL);
        sub_codec = avcodec_find_decoder(cid);
        if (!ctx || !sub_codec || avcodec_open2(ctx, sub_codec, NULL) < 0) {
            mp_msg(MSGT_SUBREADER, MSGL_FATAL,
                   "Could not open subtitle decoder\n");
            av_freep(&ctx);
            return -1;
        }
        sh->context = ctx;
    }
    res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt);
    if (res < 0)
        return res;
    if (*pts != MP_NOPTS_VALUE) {
        if (sub.end_display_time > sub.start_display_time)
            *endpts = *pts + sub.end_display_time / 1000.0;
        *pts += sub.start_display_time / 1000.0;
    }
    if (got_sub && vo_spudec && sub.num_rects == 0)
        spudec_set_paletted(vo_spudec, NULL, 0, NULL, 0, 0, 0, 0, *pts, *endpts);
    if (got_sub && sub.num_rects > 0) {
        switch (sub.rects[0]->type) {
        case SUBTITLE_BITMAP:
            if (!vo_spudec)
                vo_spudec = spudec_new_scaled(NULL, ctx->width, ctx->height, NULL, 0);
            spudec_set_paletted(vo_spudec,
                                sub.rects[0]->pict.data[0],
                                sub.rects[0]->pict.linesize[0],
                                sub.rects[0]->pict.data[1],
                                sub.rects[0]->x,
                                sub.rects[0]->y,
                                sub.rects[0]->w,
                                sub.rects[0]->h,
                                *pts,
                                *endpts);
            vo_osd_changed(OSDTYPE_SPU);
            break;
        case SUBTITLE_TEXT:
            *data = strdup(sub.rects[0]->text);
            *size = strlen(*data);
            new_type = 't';
            break;
        case SUBTITLE_ASS:
            *data = strdup(sub.rects[0]->ass);
            *size = strlen(*data);
            new_type = 'a';
            break;
        }
    }
    if (got_sub)
        avsubtitle_free(&sub);
    return new_type;
}
Exemple #13
0
static int decode_packet(AVCodecContext *dec_ctx, FILE *dst_file, AVFrame *frame, int *got_frame, int *frame_count, AVPacket *pkt)
{
    int ret = -1;
    *got_frame = 0;
    AVSubtitle sub;
    unsigned i, j, k, l;

    if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
        ret = 0;
        /* decode video frame */
        ret = avcodec_decode_video2(dec_ctx, frame, got_frame, pkt);
        if (ret < 0) {
            fprintf(stderr, "Error decoding video frame (%s)\n", av_err2str(ret));
            return ret;
        }

        if (*got_frame) {

            if (frame->width != width || frame->height != height ||
                frame->format != pix_fmt) {
                fprintf(stderr, "Error: input video width/height/format changed:\n"
                        "old: width = %d, height = %d, format = %s\n"
                        "new: width = %d, height = %d, format = %s\n",
                        width, height, av_get_pix_fmt_name(pix_fmt),
                        dec_ctx->width, dec_ctx->height,
                        av_get_pix_fmt_name(dec_ctx->pix_fmt));
                return -1;
            }

            printf("video_frame n:%d coded_n:%d pts:%s\n",
                   *frame_count, frame->coded_picture_number,
                   av_ts2timestr(frame->pts, &dec_ctx->time_base));

            /* copy decoded frame to destination buffer:
             * this is required since rawvideo expects non aligned data */
            av_image_copy(video_dst_data, video_dst_linesize,
                          (const uint8_t **)(frame->data), frame->linesize,
                          pix_fmt, width, height);
            *frame_count += 1;

            /* write to rawvideo file */
            fwrite(video_dst_data[0], 1, video_dst_bufsize, dst_file);
        }
    } else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
        ret = 0;
        /* decode audio frame */
        ret = avcodec_decode_audio4(dec_ctx, frame, got_frame, pkt);
        if (ret < 0) {
            fprintf(stderr, "Error decoding audio frame (%s)\n", av_err2str(ret));
            return ret;
        }
        /* Some audio decoders decode only part of the packet, and have to be
         * called again with the remainder of the packet data.
         * Sample: fate-suite/lossless-audio/luckynight-partial.shn
         * Also, some decoders might over-read the packet. */
        ret = FFMIN(ret, pkt->size);

        if (*got_frame) {
            size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample(frame->format);
            printf("audio_frame n:%d nb_samples:%d pts:%s\n",
                   *frame_count, frame->nb_samples,
                   av_ts2timestr(frame->pts, &dec_ctx->time_base));
            *frame_count += 1;

            /* Write the raw audio data samples of the first plane. This works
             * fine for packed formats (e.g. AV_SAMPLE_FMT_S16). However,
             * most audio decoders output planar audio, which uses a separate
             * plane of audio samples for each channel (e.g. AV_SAMPLE_FMT_S16P).
             * In other words, this code will write only the first audio channel
             * in these cases.
             * You should use libswresample or libavfilter to convert the frame
             * to packed data. */
            fwrite(frame->extended_data[0], 1, unpadded_linesize, dst_file);
        }
    } else if (dec_ctx->codec_type == AVMEDIA_TYPE_SUBTITLE) {
        ret = 0;
        /* decode video frame */
        ret = avcodec_decode_subtitle2(dec_ctx, &sub, got_frame, pkt);
        if (ret < 0) {
            fprintf(stderr, "Error decoding subtitle (%s)\n", av_err2str(ret));
            return ret;
        }

        if (*got_frame) {

            printf("subtitle n:%d format:%u pts:%s start_time:%u end_time:%u num_recs:%u\n",
                   *frame_count, sub.format,
                   av_ts2timestr(sub.pts, &dec_ctx->time_base),
                   sub.start_display_time, sub.end_display_time, sub.num_rects);

            *frame_count += 1;

            /* write to text file */
            for (i = 0; i < sub.num_rects; i += 1) {
                fprintf(dst_file, "x:%d y:%d w:%d h:%d nb_colors:%d flags:%x linesizes:%d,%d,%d,%d,%d,%d,%d,%d\n"
                        "text:%s\nass:%s\n",
                        sub.rects[i]->x, sub.rects[i]->y, sub.rects[i]->w, sub.rects[i]->h,
                        sub.rects[i]->nb_colors, sub.rects[i]->flags,
                        sub.rects[i]->pict.linesize[0], sub.rects[i]->pict.linesize[1],
                        sub.rects[i]->pict.linesize[2], sub.rects[i]->pict.linesize[3],
                        sub.rects[i]->pict.linesize[4], sub.rects[i]->pict.linesize[5],
                        sub.rects[i]->pict.linesize[6], sub.rects[i]->pict.linesize[7],
                        sub.rects[i]->text, sub.rects[i]->ass);
                for (j = 0; j < AV_NUM_DATA_POINTERS; j += 1) {
                    if (sub.rects[i]->pict.linesize[j]) {
                        fprintf(dst_file, "data:%d\n", j);
                        for (k = 0; k < sub.rects[i]->h; k += 1) {
                            for (l = 0; l < sub.rects[i]->w; l += 1) {
                                fprintf(dst_file, "%x", sub.rects[i]->pict.data[j][l + k * sub.rects[i]->pict.linesize[j]]);
                            }
                            fprintf(dst_file, "\n");
                        }
                    }
                }
            }
            avsubtitle_free(&sub);
        }
    }

    /* de-reference the frame, which is not used anymore */
    if (*got_frame)
        av_frame_unref(frame);

    return ret;
}
Exemple #14
0
   void Scheduler::process_subtitle(Display::Ptr vid)
   {
      unsigned disp_x, disp_y;
      vid->get_rect(disp_x, disp_y);
      sub_renderer->set_dimensions(disp_x, disp_y);

      for (;;)
      {
         avlock.lock();
         if (sub_pkt_queue.size() == 0)
         {
            avlock.unlock();
            break;
         }
         auto packet = sub_pkt_queue.pull();
         avlock.unlock();

         auto& pkt = packet.get();

         uint8_t *data = pkt.data;
         size_t size = pkt.size;

         int finished = 0;
         AVSubtitle sub;

         int ret;

         while (pkt.size > 0)
         {
            gfx_lock.lock();
            ret = avcodec_decode_subtitle2(file->sub().ctx, &sub, &finished, &pkt);
            gfx_lock.unlock();

            if (ret <= 0)
            {
               std::cerr << "Decode subtitle failed." << std::endl;
               break;
            }

            pkt.data += ret;
            pkt.size -= ret;
         }
         pkt.data = data;
         pkt.size = size;

         if (finished)
         {
            for (unsigned i = 0; i < sub.num_rects; i++)
            {
               if (sub.rects[i]->ass)
               {
                  // Push our new message to handler queue. We just handle ASS atm, but hey ;)
                  gfx_lock.lock();
                  sub_renderer->push_msg(sub.rects[i]->ass, video_pts);
                  gfx_lock.unlock();
               }
            }
         }
         else
         {
            std::cout << "Did not finish a subtitle frame." << std::endl;
         }

         avsubtitle_free(&sub);
      }

      // Print all subtitle currently active in this PTS to screen.
      gfx_lock.lock();
      auto& list = sub_renderer->msg_list(video_pts);

      for (auto& msg : list)
         vid->subtitle(msg);

      gfx_lock.unlock();
   }
Exemple #15
0
void AbstractStream::deleteSubtitle(AVSubtitle *subtitle)
{
    avsubtitle_free(subtitle);
    delete subtitle;
}
bool SubtitleProcessorFFmpeg::processSubtitle()
{
    m_frames.clear();
    int ss = m_reader.subtitleStream();
    if (ss < 0) {
        qWarning("no subtitle stream found");
        return false;
    }
    AVCodecContext *ctx = m_reader.subtitleCodecContext();
    AVCodec *dec = avcodec_find_decoder(ctx->codec_id);
    if (!dec) {
        qWarning("Failed to find subtitle codec %s", avcodec_get_name(ctx->codec_id));
        return false;
    }
    const AVCodecDescriptor *dec_desc = avcodec_descriptor_get(ctx->codec_id);
    if (dec_desc && !(dec_desc->props & AV_CODEC_PROP_TEXT_SUB)) {
        qWarning("Only text based subtitles are currently supported");
        return false;
    }
    AVDictionary *codec_opts = NULL;
    int ret = avcodec_open2(ctx, dec, &codec_opts);
    if (ret < 0) {
        qWarning("open subtitle codec error: %s", av_err2str(ret));
        av_dict_free(&codec_opts);
        return false;
    }
    while (!m_reader.atEnd()) {
        if (!m_reader.readFrame())
            continue;
        if (!m_reader.packet()->isValid())
            continue;
        if (m_reader.stream() != ss)
            continue;
        AVPacket packet;
        av_init_packet(&packet);
        packet.size = m_reader.packet()->data.size();
        packet.data = (uint8_t*)m_reader.packet()->data.constData();
        int got_subtitle = 0;
        AVSubtitle sub;
        memset(&sub, 0, sizeof(sub));
        ret = avcodec_decode_subtitle2(ctx, &sub, &got_subtitle, &packet);
        if (ret < 0 || !got_subtitle) {
            av_free_packet(&packet);
            avsubtitle_free(&sub);
            continue;
        }
        qreal pts = m_reader.packet()->pts;
        SubtitleFrame frame;
        frame.begin = pts + qreal(sub.start_display_time)/1000.0;
        frame.end = pts + qreal(sub.end_display_time)/1000.0;
       // qDebug() << QTime(0, 0, 0).addMSecs(frame.begin*1000.0) << "-" << QTime(0, 0, 0).addMSecs(frame.end*1000.0) << " fmt: " << sub.format << " pts: " << m_reader.packet()->pts //sub.pts
        //            << " rects: " << sub.num_rects;
        for (unsigned i = 0; i < sub.num_rects; i++) {
            switch (sub.rects[i]->type) {
            case SUBTITLE_ASS:
                frame.text.append(PlainText::fromAss(sub.rects[i]->ass)).append('\n');
                break;
            case SUBTITLE_TEXT:
                frame.text.append(sub.rects[i]->text).append('\n');
                break;
            case SUBTITLE_BITMAP:
                break;
            default:
                break;
            }
        }
        m_frames.append(frame);
        av_free_packet(&packet);
        avsubtitle_free(&sub);
    }
    avcodec_close(ctx);
    return true;
}
Exemple #17
0
static av_cold int init_subtitles(AVFilterContext *ctx)
{
    int j, ret, sid;
    int k = 0;
    AVDictionary *codec_opts = NULL;
    AVFormatContext *fmt = NULL;
    AVCodecContext *dec_ctx = NULL;
    AVCodec *dec = NULL;
    const AVCodecDescriptor *dec_desc;
    AVStream *st;
    AVPacket pkt;
    AssContext *ass = ctx->priv;

    /* Init libass */
    ret = init(ctx);
    if (ret < 0)
        return ret;
    ass->track = ass_new_track(ass->library);
    if (!ass->track) {
        av_log(ctx, AV_LOG_ERROR, "Could not create a libass track\n");
        return AVERROR(EINVAL);
    }

    /* Open subtitles file */
    ret = avformat_open_input(&fmt, ass->filename, NULL, NULL);
    if (ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Unable to open %s\n", ass->filename);
        goto end;
    }
    ret = avformat_find_stream_info(fmt, NULL);
    if (ret < 0)
        goto end;

    /* Locate subtitles stream */
    if (ass->stream_index < 0)
        ret = av_find_best_stream(fmt, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0);
    else {
        ret = -1;
        if (ass->stream_index < fmt->nb_streams) {
            for (j = 0; j < fmt->nb_streams; j++) {
                if (fmt->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
                    if (ass->stream_index == k) {
                        ret = j;
                        break;
                    }
                    k++;
                }
            }
        }
    }

    if (ret < 0) {
        av_log(ctx, AV_LOG_ERROR, "Unable to locate subtitle stream in %s\n",
               ass->filename);
        goto end;
    }
    sid = ret;
    st = fmt->streams[sid];

    /* Load attached fonts */
    for (j = 0; j < fmt->nb_streams; j++) {
        AVStream *st = fmt->streams[j];
        if (st->codecpar->codec_type == AVMEDIA_TYPE_ATTACHMENT &&
            attachment_is_font(st)) {
            const AVDictionaryEntry *tag = NULL;
            tag = av_dict_get(st->metadata, "filename", NULL,
                              AV_DICT_MATCH_CASE);

            if (tag) {
                av_log(ctx, AV_LOG_DEBUG, "Loading attached font: %s\n",
                       tag->value);
                ass_add_font(ass->library, tag->value,
                             st->codecpar->extradata,
                             st->codecpar->extradata_size);
            } else {
                av_log(ctx, AV_LOG_WARNING,
                       "Font attachment has no filename, ignored.\n");
            }
        }
    }

    /* Initialize fonts */
    ass_set_fonts(ass->renderer, NULL, NULL, 1, NULL, 1);

    /* Open decoder */
    dec = avcodec_find_decoder(st->codecpar->codec_id);
    if (!dec) {
        av_log(ctx, AV_LOG_ERROR, "Failed to find subtitle codec %s\n",
               avcodec_get_name(st->codecpar->codec_id));
        return AVERROR(EINVAL);
    }
    dec_desc = avcodec_descriptor_get(st->codecpar->codec_id);
    if (dec_desc && !(dec_desc->props & AV_CODEC_PROP_TEXT_SUB)) {
        av_log(ctx, AV_LOG_ERROR,
               "Only text based subtitles are currently supported\n");
        return AVERROR_PATCHWELCOME;
    }
    if (ass->charenc)
        av_dict_set(&codec_opts, "sub_charenc", ass->charenc, 0);
    if (LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(57,26,100))
        av_dict_set(&codec_opts, "sub_text_format", "ass", 0);

    dec_ctx = avcodec_alloc_context3(dec);
    if (!dec_ctx)
        return AVERROR(ENOMEM);

    ret = avcodec_parameters_to_context(dec_ctx, st->codecpar);
    if (ret < 0)
        goto end;

    /*
     * This is required by the decoding process in order to rescale the
     * timestamps: in the current API the decoded subtitles have their pts
     * expressed in AV_TIME_BASE, and thus the lavc internals need to know the
     * stream time base in order to achieve the rescaling.
     *
     * That API is old and needs to be reworked to match behaviour with A/V.
     */
    av_codec_set_pkt_timebase(dec_ctx, st->time_base);

    ret = avcodec_open2(dec_ctx, NULL, &codec_opts);
    if (ret < 0)
        goto end;

    if (ass->force_style) {
        char **list = NULL;
        char *temp = NULL;
        char *ptr = av_strtok(ass->force_style, ",", &temp);
        int i = 0;
        while (ptr) {
            av_dynarray_add(&list, &i, ptr);
            if (!list) {
                ret = AVERROR(ENOMEM);
                goto end;
            }
            ptr = av_strtok(NULL, ",", &temp);
        }
        av_dynarray_add(&list, &i, NULL);
        if (!list) {
            ret = AVERROR(ENOMEM);
            goto end;
        }
        ass_set_style_overrides(ass->library, list);
        av_free(list);
    }
    /* Decode subtitles and push them into the renderer (libass) */
    if (dec_ctx->subtitle_header)
        ass_process_codec_private(ass->track,
                                  dec_ctx->subtitle_header,
                                  dec_ctx->subtitle_header_size);
    av_init_packet(&pkt);
    pkt.data = NULL;
    pkt.size = 0;
    while (av_read_frame(fmt, &pkt) >= 0) {
        int i, got_subtitle;
        AVSubtitle sub = {0};

        if (pkt.stream_index == sid) {
            ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_subtitle, &pkt);
            if (ret < 0) {
                av_log(ctx, AV_LOG_WARNING, "Error decoding: %s (ignored)\n",
                       av_err2str(ret));
            } else if (got_subtitle) {
                const int64_t start_time = av_rescale_q(sub.pts, AV_TIME_BASE_Q, av_make_q(1, 1000));
                const int64_t duration   = sub.end_display_time;
                for (i = 0; i < sub.num_rects; i++) {
                    char *ass_line = sub.rects[i]->ass;
                    if (!ass_line)
                        break;
                    if (LIBAVCODEC_VERSION_INT < AV_VERSION_INT(57,25,100))
                        ass_process_data(ass->track, ass_line, strlen(ass_line));
                    else
                        ass_process_chunk(ass->track, ass_line, strlen(ass_line),
                                          start_time, duration);
                }
            }
        }
        av_packet_unref(&pkt);
        avsubtitle_free(&sub);
    }

end:
    av_dict_free(&codec_opts);
    avcodec_close(dec_ctx);
    avcodec_free_context(&dec_ctx);
    avformat_close_input(&fmt);
    return ret;
}
void SubtitleReader::FreeAVSubtitle(const AVSubtitle &subtitle)
{
    avsubtitle_free(const_cast<AVSubtitle*>(&subtitle));
}
Exemple #19
0
// Initialize sub from sub->avsub.
static void read_sub_bitmaps(struct sd *sd, struct sub *sub)
{
    struct MPOpts *opts = sd->opts;
    struct sd_lavc_priv *priv = sd->priv;
    AVSubtitle *avsub = &sub->avsub;

    MP_TARRAY_GROW(priv, sub->inbitmaps, avsub->num_rects);

    packer_set_size(priv->packer, avsub->num_rects);

    // If we blur, we want a transparent region around the bitmap data to
    // avoid "cut off" artifacts on the borders.
    bool apply_blur = opts->sub_gauss != 0.0f;
    int extend = apply_blur ? 5 : 0;
    // Assume consumers may use bilinear scaling on it (2x2 filter)
    int padding = 1 + extend;

    priv->packer->padding = padding;

    // For the sake of libswscale, which in some cases takes sub-rects as
    // source images, and wants 16 byte start pointer and stride alignment.
    int align = 4;

    for (int i = 0; i < avsub->num_rects; i++) {
        struct AVSubtitleRect *r = avsub->rects[i];
        struct sub_bitmap *b = &sub->inbitmaps[sub->count];

        if (r->type != SUBTITLE_BITMAP) {
            MP_ERR(sd, "unsupported subtitle type from libavcodec\n");
            continue;
        }
        if (!(r->flags & AV_SUBTITLE_FLAG_FORCED) && opts->forced_subs_only)
            continue;
        if (r->w <= 0 || r->h <= 0)
            continue;

        b->bitmap = r; // save for later (dumb hack to avoid more complexity)

        priv->packer->in[sub->count] = (struct pos){r->w + (align - 1), r->h};
        sub->count++;
    }

    priv->packer->count = sub->count;

    if (packer_pack(priv->packer) < 0) {
        MP_ERR(sd, "Unable to pack subtitle bitmaps.\n");
        sub->count = 0;
    }

    if (!sub->count)
        return;

    struct pos bb[2];
    packer_get_bb(priv->packer, bb);

    sub->bound_w = bb[1].x;
    sub->bound_h = bb[1].y;

    if (!sub->data || sub->data->w < sub->bound_w || sub->data->h < sub->bound_h) {
        talloc_free(sub->data);
        sub->data = mp_image_alloc(IMGFMT_BGRA, priv->packer->w, priv->packer->h);
        if (!sub->data) {
            sub->count = 0;
            return;
        }
        talloc_steal(priv, sub->data);
    }

    for (int i = 0; i < sub->count; i++) {
        struct sub_bitmap *b = &sub->inbitmaps[i];
        struct pos pos = priv->packer->result[i];
        struct AVSubtitleRect *r = b->bitmap;
#if HAVE_AV_SUBTITLE_NOPICT
        uint8_t **data = r->data;
        int *linesize = r->linesize;
#else
        uint8_t **data = r->pict.data;
        int *linesize = r->pict.linesize;
#endif
        b->w = r->w;
        b->h = r->h;
        b->x = r->x;
        b->y = r->y;

        // Choose such that the extended start position is aligned.
        pos.x = MP_ALIGN_UP(pos.x - extend, align) + extend;

        b->src_x = pos.x;
        b->src_y = pos.y;
        b->stride = sub->data->stride[0];
        b->bitmap = sub->data->planes[0] + pos.y * b->stride + pos.x * 4;

        sub->src_w = FFMAX(sub->src_w, b->x + b->w);
        sub->src_h = FFMAX(sub->src_h, b->y + b->h);

        assert(r->nb_colors > 0);
        assert(r->nb_colors <= 256);
        uint32_t pal[256] = {0};
        memcpy(pal, data[1], r->nb_colors * 4);
        convert_pal(pal, 256, opts->sub_gray);

        for (int y = -padding; y < b->h + padding; y++) {
            uint32_t *out = (uint32_t*)((char*)b->bitmap + y * b->stride);
            int start = 0;
            for (int x = -padding; x < 0; x++)
                out[x] = 0;
            if (y >= 0 && y < b->h) {
                uint8_t *in = data[0] + y * linesize[0];
                for (int x = 0; x < b->w; x++)
                    *out++ = pal[*in++];
                start = b->w;
            }
            for (int x = start; x < b->w + padding; x++)
                *out++ = 0;
        }

        b->bitmap = (char*)b->bitmap - extend * b->stride - extend * 4;
        b->src_x -= extend;
        b->src_y -= extend;
        b->x -= extend;
        b->y -= extend;
        b->w += extend * 2;
        b->h += extend * 2;

        if (apply_blur)
            mp_blur_rgba_sub_bitmap(b, opts->sub_gauss);
    }
}

static void decode(struct sd *sd, struct demux_packet *packet)
{
    struct MPOpts *opts = sd->opts;
    struct sd_lavc_priv *priv = sd->priv;
    AVCodecContext *ctx = priv->avctx;
    double pts = packet->pts;
    double endpts = MP_NOPTS_VALUE;
    double duration = packet->duration;
    AVSubtitle sub;
    AVPacket pkt;

    // libavformat sets duration==0, even if the duration is unknown. Some files
    // also have actually subtitle packets with duration explicitly set to 0
    // (yes, at least some of such mkv files were muxed by libavformat).
    // Assume there are no bitmap subs that actually use duration==0 for
    // hidden subtitle events.
    if (duration == 0)
        duration = -1;

    if (pts == MP_NOPTS_VALUE)
        MP_WARN(sd, "Subtitle with unknown start time.\n");

    mp_set_av_packet(&pkt, packet, &priv->pkt_timebase);
    int got_sub;
    int res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt);
    if (res < 0 || !got_sub)
        return;

    if (sub.pts != AV_NOPTS_VALUE)
        pts = sub.pts / (double)AV_TIME_BASE;

    if (pts != MP_NOPTS_VALUE) {
        if (sub.end_display_time > sub.start_display_time &&
            sub.end_display_time != UINT32_MAX)
        {
            duration = (sub.end_display_time - sub.start_display_time) / 1000.0;
        }
        pts += sub.start_display_time / 1000.0;

        if (duration >= 0)
            endpts = pts + duration;

        // set end time of previous sub
        struct sub *prev = &priv->subs[0];
        if (prev->valid) {
            if (prev->endpts == MP_NOPTS_VALUE || prev->endpts > pts)
                prev->endpts = pts;

            if (opts->sub_fix_timing && pts - prev->endpts <= SUB_GAP_THRESHOLD)
                prev->endpts = pts;

            for (int n = 0; n < priv->num_seekpoints; n++) {
                if (priv->seekpoints[n].pts == prev->pts) {
                    priv->seekpoints[n].endpts = prev->endpts;
                    break;
                }
            }
        }

        // This subtitle packet only signals the end of subtitle display.
        if (!sub.num_rects) {
            avsubtitle_free(&sub);
            return;
        }
    }

    alloc_sub(priv);
    struct sub *current = &priv->subs[0];

    current->valid = true;
    current->pts = pts;
    current->endpts = endpts;
    current->avsub = sub;

    read_sub_bitmaps(sd, current);

    if (pts != MP_NOPTS_VALUE) {
        for (int n = 0; n < priv->num_seekpoints; n++) {
            if (priv->seekpoints[n].pts == pts)
                goto skip;
        }
        // Set arbitrary limit as safe-guard against insane files.
        if (priv->num_seekpoints >= 10000)
            MP_TARRAY_REMOVE_AT(priv->seekpoints, priv->num_seekpoints, 0);
        MP_TARRAY_APPEND(priv, priv->seekpoints, priv->num_seekpoints,
                         (struct seekpoint){.pts = pts, .endpts = endpts});
        skip: ;
    }
}
static void *ass_reader_thread(void *)
{
	set_threadname("ass_reader_thread");
	while (!sem_wait(&ass_sem)) {
		if (!ass_reader_running)
			break;

		ass_data *a = (ass_data *) ass_queue.pop();
		if (!a) {
			if (!ass_reader_running)
				break;
			continue;
		}

		OpenThreads::ScopedLock<OpenThreads::Mutex> m_lock(ass_mutex);
		std::map<int,ASS_Track*>::iterator it = ass_map.find(a->pid);
		ASS_Track *track;
		if (it == ass_map.end()) {
			CFrameBuffer *fb = CFrameBuffer::getInstance();
			int xres = fb->getScreenWidth(true);
			int yres = fb->getScreenHeight(true);
			if (!ass_library) {
				ass_library = ass_library_init();
				ass_set_extract_fonts(ass_library, 1);
				ass_set_style_overrides(ass_library, NULL);
				ass_renderer = ass_renderer_init(ass_library);
				ass_set_frame_size(ass_renderer, xres, yres);
				ass_set_margins(ass_renderer, 3 * yres / 100, 3 * yres / 100, 3 * xres / 100, 3 * xres / 100);
				ass_set_use_margins(ass_renderer, 1);
				ass_set_hinting(ass_renderer, ASS_HINTING_LIGHT);
				ass_set_aspect_ratio(ass_renderer, 1.0, 1.0);
				ass_font = *sub_font_file;
				ass_set_fonts(ass_renderer, ass_font.c_str(), "Arial", 0, NULL, 1);
			}
			track = ass_new_track(ass_library);
			track->PlayResX = xres;
			track->PlayResY = yres;
			ass_size = sub_font_size;
			ass_set_font_scale(ass_renderer, ((double) ass_size)/ASS_CUSTOM_FONT_SIZE);
			if (a->c->subtitle_header) {
				std::string ass_hdr = ass_subtitle_header_default();
				if (ass_hdr.compare((char*) a->c->subtitle_header)) {
					ass_process_codec_private(track, (char *) a->c->subtitle_header, a->c->subtitle_header_size);
				} else {
					// This is the FFMPEG default ASS header. Use something more suitable instead:
					ass_hdr = ass_subtitle_header_custom();
					ass_process_codec_private(track, (char *) ass_hdr.c_str(), ass_hdr.length());
				}
			}
			ass_map[a->pid] = track;
			if (a->pid == dvbsub_pid)
				ass_track = track;
//fprintf(stderr, "### got subtitle track %d, subtitle header: \n---\n%s\n---\n", pid, c->subtitle_header);
		} else
			track = it->second;
		for (unsigned int i = 0; i < a->sub.num_rects; i++)
			if (a->sub.rects[i]->ass)
				ass_process_data(track, a->sub.rects[i]->ass, strlen(a->sub.rects[i]->ass));
		avsubtitle_free(&a->sub);
		delete a;
	}
	ass_reader_running = false;
	pthread_exit(NULL);
}
Exemple #21
0
int SubtitleDecoder::subtitle_thread(void *arg)
{
    VideoState *is = (VideoState*)arg;
    Frame *sp;
    int got_subtitle;
    double pts;
    int i;

    for (;;) {
        if (!(sp = is->subpq().peek_writable()))
            return 0;

        if ((got_subtitle = is->subdec(). decode_frame((AVFrame*) &sp->sub)) < 0)
            break;

        pts = 0;

        if (got_subtitle && sp->sub.format == 0) {
            if (sp->sub.pts != AV_NOPTS_VALUE)
                pts = sp->sub.pts / (double)AV_TIME_BASE;
            sp->pts = pts;
            sp->serial = is->subdec().pkt_serial;

            for (i = 0; i < sp->sub.num_rects; i++)
            {
                int in_w = sp->sub.rects[i]->w;
                int in_h = sp->sub.rects[i]->h;
                int subw = is->subdec().avctx->width  ? is->subdec().avctx->width  : is->decoders.viddec_width;
                int subh = is->subdec().avctx->height ? is->subdec().avctx->height : is->decoders.viddec_height;
                int out_w = is->decoders.viddec_width  ? in_w * is->decoders.viddec_width  / subw : in_w;
                int out_h = is->decoders.viddec_height ? in_h * is->decoders.viddec_height / subh : in_h;
                AVPicture newpic;

                //can not use avpicture_alloc as it is not compatible with avsubtitle_free()
                av_image_fill_linesizes(newpic.linesize, AV_PIX_FMT_YUVA420P, out_w);
                newpic.data[0] = (uint8_t*) av_malloc(newpic.linesize[0] * out_h);
                newpic.data[3] = (uint8_t*) av_malloc(newpic.linesize[3] * out_h);
                newpic.data[1] = (uint8_t*) av_malloc(newpic.linesize[1] * ((out_h+1)/2));
                newpic.data[2] = (uint8_t*) av_malloc(newpic.linesize[2] * ((out_h+1)/2));

                is->sub_convert_ctx = sws_getCachedContext(is->sub_convert_ctx,
                    in_w, in_h, AV_PIX_FMT_PAL8, out_w, out_h,
                    AV_PIX_FMT_YUVA420P, sws_flags, NULL, NULL, NULL);
                if (!is->sub_convert_ctx || !newpic.data[0] || !newpic.data[3] ||
                    !newpic.data[1] || !newpic.data[2]
                ) {
                    av_log(NULL, AV_LOG_FATAL, "Cannot initialize the sub conversion context\n");
                    exit(1);
                }
                sws_scale(is->sub_convert_ctx,
                          (const uint8_t* const*)sp->sub.rects[i]->pict.data, sp->sub.rects[i]->pict.linesize,
                          0, in_h, newpic.data, newpic.linesize);

                av_free(sp->sub.rects[i]->pict.data[0]);
                av_free(sp->sub.rects[i]->pict.data[1]);
                sp->sub.rects[i]->pict = newpic;
                sp->sub.rects[i]->w = out_w;
                sp->sub.rects[i]->h = out_h;
                sp->sub.rects[i]->x = sp->sub.rects[i]->x * out_w / in_w;
                sp->sub.rects[i]->y = sp->sub.rects[i]->y * out_h / in_h;
            }

            /* now we can update the picture count */
            is->subpq().push();
        } else if (got_subtitle) {
            avsubtitle_free(&sp->sub);
        }
    }
    return 0;
}
Exemple #22
0
bool FFDecSW::decodeSubtitle( const QByteArray &encoded, double pts, double pos, QMPlay2_OSD *&osd, int w, int h )
{
	if ( codec_ctx->codec_type != AVMEDIA_TYPE_SUBTITLE )
		return false;

	if ( encoded.isEmpty() )
	{
		getFromBitmapSubsBuffer( osd, pos );
		return true;
	}

	AVPacket packet;
	av_new_packet( &packet, encoded.size() );
	memcpy( packet.data, encoded.data(), encoded.size() );

	bool ret = true;
	int got_sub_ptr;
	AVSubtitle subtitle;
	if ( avcodec_decode_subtitle2( codec_ctx, &subtitle, &got_sub_ptr, &packet ) && got_sub_ptr )
	{
		for ( unsigned i = 0 ; i < subtitle.num_rects ; i++ )
		{
			AVSubtitleRect *rect = subtitle.rects[ i ];
			switch ( rect->type )
			{
				case SUBTITLE_BITMAP:
				{
					BitmapSubBuffer *buff = new BitmapSubBuffer;
					buff->duration = ( subtitle.end_display_time - subtitle.start_display_time ) / 1000.0;
					buff->pts = subtitle.start_display_time ? subtitle.start_display_time / 1000.0 : ( pts < 0.0 ? 0.0 : pts );
					buff->w = av_clip( rect->w, 0, w );
					buff->h = av_clip( rect->h, 0, h );
					buff->x = av_clip( rect->x, 0, w - buff->w );
					buff->y = av_clip( rect->y, 0, h - buff->h );
					buff->bitmap.resize( ( buff->w * buff->h ) << 2 );

					uint8_t  *source  = ( uint8_t * )rect->pict.data[ 0 ];
					uint32_t *palette = ( uint32_t * )rect->pict.data[ 1 ];
					uint32_t *dest    = ( uint32_t * )buff->bitmap.data();

					for ( int y = 0 ; y < buff->h ; y++ )
						for ( int x = 0 ; x < buff->w ; x++ )
							dest[ y * buff->w + x ] = palette[ source[ y * rect->pict.linesize[ 0 ] + x ] ];

					if ( buff->pts <= pos )
						while ( bitmapSubBuffer.size() )
							delete bitmapSubBuffer.takeFirst();
					bitmapSubBuffer += buff;
					getFromBitmapSubsBuffer( osd, pos );
				} break;
				default:
					ret = false;
					break;
			}
		}
		avsubtitle_free( &subtitle );
	}

	av_free_packet( &packet );

	return ret;
}
Exemple #23
0
static void decode(struct sh_sub *sh, struct osd_state *osd, void *data,
                   int data_len, double pts, double duration)
{
    struct sd_lavc_priv *priv = sh->context;
    AVCodecContext *ctx = priv->avctx;
    AVSubtitle sub;
    AVPacket pkt;

    clear(priv);
    av_init_packet(&pkt);
    pkt.data = data;
    pkt.size = data_len;
    pkt.pts = pts * 1000;
    if (duration >= 0)
        pkt.convergence_duration = duration * 1000;
    int got_sub;
    int res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt);
    if (res < 0 || !got_sub)
        return;
    if (pts != MP_NOPTS_VALUE) {
        if (sub.end_display_time > sub.start_display_time)
            duration = (sub.end_display_time - sub.start_display_time) / 1000.0;
        pts += sub.start_display_time / 1000.0;
    }
    double endpts = MP_NOPTS_VALUE;
    if (pts != MP_NOPTS_VALUE && duration >= 0)
        endpts = pts + duration;
    if (vo_spudec && sub.num_rects == 0)
        spudec_set_paletted(vo_spudec, NULL, 0, NULL, 0, 0, 0, 0, pts, endpts);
    if (sub.num_rects > 0) {
        switch (sub.rects[0]->type) {
        case SUBTITLE_BITMAP:
            // Assume resolution heuristics only work for PGS and DVB
            if (!osd->support_rgba || sh->type != 'p' && sh->type != 'b') {
                if (!vo_spudec)
                    vo_spudec = spudec_new_scaled(NULL, ctx->width, ctx->height,
                                                  NULL, 0);
                old_avsub_to_spudec(sub.rects, sub.num_rects, pts, endpts);
                vo_osd_changed(OSDTYPE_SPU);
                break;
            }
            priv->inbitmaps = talloc_array(priv, struct sub_bitmap,
                                           sub.num_rects);
            for (int i = 0; i < sub.num_rects; i++) {
                struct AVSubtitleRect *r = sub.rects[i];
                struct sub_bitmap *b = &priv->inbitmaps[i];
                uint32_t *outbmp = talloc_size(priv->inbitmaps,
                                               r->w * r->h * 4);
                b->bitmap = outbmp;
                b->w = r->w;
                b->h = r->h;
                b->x = r->x;
                b->y = r->y;
                uint8_t *inbmp = r->pict.data[0];
                uint32_t *palette = (uint32_t *) r->pict.data[1];
                for (int y = 0; y < r->h; y++) {
                    for (int x = 0; x < r->w; x++)
                        *outbmp++ = palette[*inbmp++];
                    inbmp += r->pict.linesize[0] - r->w;
                };
            }
            priv->count = sub.num_rects;
            priv->endpts = endpts;
            break;
        default:
            mp_msg(MSGT_SUBREADER, MSGL_ERR, "sd_lavc: unsupported subtitle "
                   "type from libavcodec\n");
            break;
        }
    }
    avsubtitle_free(&sub);
}
cDvbSubtitleBitmaps::~cDvbSubtitleBitmaps()
{
//    dbgconverter("cDvbSubtitleBitmaps::delete: PTS: %lld rects %d\n", pts, Count());
	avsubtitle_free(&sub);
}
Exemple #25
0
void lavc_conv_uninit(struct lavc_conv *priv)
{
    avsubtitle_free(&priv->cur);
    avcodec_free_context(&priv->avctx);
    talloc_free(priv);
}
Exemple #26
0
static void decode(struct sd *sd, struct demux_packet *packet)
{
    struct MPOpts *opts = sd->opts;
    struct sd_lavc_priv *priv = sd->priv;
    AVCodecContext *ctx = priv->avctx;
    double pts = packet->pts;
    double endpts = MP_NOPTS_VALUE;
    double duration = packet->duration;
    AVSubtitle sub;
    AVPacket pkt;

    // libavformat sets duration==0, even if the duration is unknown. Some files
    // also have actually subtitle packets with duration explicitly set to 0
    // (yes, at least some of such mkv files were muxed by libavformat).
    // Assume there are no bitmap subs that actually use duration==0 for
    // hidden subtitle events.
    if (duration == 0)
        duration = -1;

    if (pts == MP_NOPTS_VALUE)
        MP_WARN(sd, "Subtitle with unknown start time.\n");

    mp_set_av_packet(&pkt, packet, &priv->pkt_timebase);
    int got_sub;
    int res = avcodec_decode_subtitle2(ctx, &sub, &got_sub, &pkt);
    if (res < 0 || !got_sub)
        return;

    if (sub.pts != AV_NOPTS_VALUE)
        pts = sub.pts / (double)AV_TIME_BASE;

    if (pts != MP_NOPTS_VALUE) {
        if (sub.end_display_time > sub.start_display_time &&
            sub.end_display_time != UINT32_MAX)
        {
            duration = (sub.end_display_time - sub.start_display_time) / 1000.0;
        }
        pts += sub.start_display_time / 1000.0;

        if (duration >= 0)
            endpts = pts + duration;

        // set end time of previous sub
        struct sub *prev = &priv->subs[0];
        if (prev->valid) {
            if (prev->endpts == MP_NOPTS_VALUE || prev->endpts > pts)
                prev->endpts = pts;

            if (opts->sub_fix_timing && pts - prev->endpts <= SUB_GAP_THRESHOLD)
                prev->endpts = pts;

            for (int n = 0; n < priv->num_seekpoints; n++) {
                if (priv->seekpoints[n].pts == prev->pts) {
                    priv->seekpoints[n].endpts = prev->endpts;
                    break;
                }
            }
        }

        // This subtitle packet only signals the end of subtitle display.
        if (!sub.num_rects) {
            avsubtitle_free(&sub);
            return;
        }
    }

    alloc_sub(priv);
    struct sub *current = &priv->subs[0];

    current->valid = true;
    current->pts = pts;
    current->endpts = endpts;
    current->avsub = sub;

    MP_TARRAY_GROW(priv, current->inbitmaps, sub.num_rects);
    MP_TARRAY_GROW(priv, current->imgs, sub.num_rects);

    for (int i = 0; i < sub.num_rects; i++) {
        struct AVSubtitleRect *r = sub.rects[i];
        struct sub_bitmap *b = &current->inbitmaps[current->count];
        struct osd_bmp_indexed *img = &current->imgs[current->count];
        if (r->type != SUBTITLE_BITMAP) {
            MP_ERR(sd, "unsupported subtitle type from libavcodec\n");
            continue;
        }
        if (!(r->flags & AV_SUBTITLE_FLAG_FORCED) && opts->forced_subs_only)
            continue;
        if (r->w <= 0 || r->h <= 0)
            continue;
#if HAVE_AV_SUBTITLE_NOPICT
        uint8_t **data = r->data;
        int *linesize = r->linesize;
#else
        uint8_t **data = r->pict.data;
        int *linesize = r->pict.linesize;
#endif
        img->bitmap = data[0];
        assert(r->nb_colors > 0);
        assert(r->nb_colors * 4 <= sizeof(img->palette));
        memcpy(img->palette, data[1], r->nb_colors * 4);
        b->bitmap = img;
        b->stride = linesize[0];
        b->w = r->w;
        b->h = r->h;
        b->x = r->x;
        b->y = r->y;
        current->count++;
    }

    if (pts != MP_NOPTS_VALUE) {
        for (int n = 0; n < priv->num_seekpoints; n++) {
            if (priv->seekpoints[n].pts == pts)
                goto skip;
        }
        // Set arbitrary limit as safe-guard against insane files.
        if (priv->num_seekpoints >= 10000)
            MP_TARRAY_REMOVE_AT(priv->seekpoints, priv->num_seekpoints, 0);
        MP_TARRAY_APPEND(priv, priv->seekpoints, priv->num_seekpoints,
                         (struct seekpoint){.pts = pts, .endpts = endpts});
        skip: ;
    }
SubtitleFrame SubtitleProcessorFFmpeg::processLine(const QByteArray &data, qreal pts, qreal duration)
{
    // AV_CODEC_ID_xxx and srt, subrip are available for ffmpeg >= 1.0. AV_CODEC_ID_xxx
    // TODO: what about other formats?
    // libav-9: packet data from demuxer contains time and but duration is 0, must decode
    if (duration > 0 && (!codec_ctx
#if QTAV_USE_FFMPEG(LIBAVCODEC)
            || codec_ctx->codec_id == AV_CODEC_ID_SUBRIP
#endif
            || codec_ctx->codec_id == AV_CODEC_ID_SRT
            )) {
        SubtitleFrame f;
        f.begin = pts;
        f.end = pts + duration;
        if (data.startsWith("Dialogue:")) // e.g. decoding embedded subtitles
            f.text = PlainText::fromAss(data.constData());
        else
            f.text = QString::fromUtf8(data.constData(), data.size()); //utf-8 is required
        return f;
    }
    AVPacket packet;
    av_init_packet(&packet);
    packet.size = data.size();
    packet.data = (uint8_t*)data.constData();
    /*
     * ffmpeg <2.5: AVPakcet.data has original text including time info, decoder use that info to get correct time
     * "Dialogue: 0,0:00:20.21,0:00:22.96,*Default,NTP,0000,0000,0000,blablabla
     * ffmpeg >=2.5: AVPakcet.data changed, we have to set correct pts & duration for packet to be decoded
     * 16,0,*Default,NTP,0000,0000,0000,,blablabla
     */
    const double unit = 1.0/av_q2d(codec_ctx->time_base); //time_base is deprecated, use framerate since 17085a0, check FF_API_AVCTX_TIMEBASE
    packet.pts = pts * unit;
    packet.duration = duration * unit;
    AVSubtitle sub;
    memset(&sub, 0, sizeof(sub));
    int got_subtitle = 0;
    int ret = avcodec_decode_subtitle2(codec_ctx, &sub, &got_subtitle, &packet);
    if (ret < 0 || !got_subtitle) {
        av_free_packet(&packet);
        avsubtitle_free(&sub);
        return SubtitleFrame();
    }
    SubtitleFrame frame;
    // start_display_time and duration are in ms
    frame.begin = pts + qreal(sub.start_display_time)/1000.0;
    frame.end = pts + qreal(sub.end_display_time)/1000.0;
    //qDebug() << QTime(0, 0, 0).addMSecs(frame.begin*1000.0) << "-" << QTime(0, 0, 0).addMSecs(frame.end*1000.0) << " fmt: " << sub.format << " pts: " << m_reader.packet().pts //sub.pts
      //       << " rects: " << sub.num_rects << " end: " << sub.end_display_time;
    for (unsigned i = 0; i < sub.num_rects; i++) {
        switch (sub.rects[i]->type) {
        case SUBTITLE_ASS:
            //qDebug("frame: %s", sub.rects[i]->ass);
            frame.text.append(PlainText::fromAss(sub.rects[i]->ass)).append('\n');
            break;
        case SUBTITLE_TEXT:
            //qDebug("frame: %s", sub.rects[i]->text);
            frame.text.append(sub.rects[i]->text).append('\n');
            break;
        case SUBTITLE_BITMAP:
            break;
        default:
            break;
        }
    }
    av_free_packet(&packet);
    avsubtitle_free(&sub);
    return frame;
}
Exemple #28
0
/**
 * Decode subtitles from LAVC
 */
static void
video_subtitles_lavc(media_pipe_t *mp, media_buf_t *mb,
		     AVCodecContext *ctx)
{
  AVSubtitle sub;
  int got_sub = 0, i, x, y;
  video_overlay_t *vo;

  AVPacket avpkt;
  av_init_packet(&avpkt);
  avpkt.data = mb->mb_data;
  avpkt.size = mb->mb_size;

  if(avcodec_decode_subtitle2(ctx, &sub, &got_sub, &avpkt) < 1 || !got_sub) 
    return;

  if(sub.num_rects == 0) {
    // Flush screen
    vo = calloc(1, sizeof(video_overlay_t));
    vo->vo_type = VO_TIMED_FLUSH;
    vo->vo_start = mb->mb_pts + sub.start_display_time * 1000;
    video_overlay_enqueue(mp, vo);
  } else {

    for(i = 0; i < sub.num_rects; i++) {
      AVSubtitleRect *r = sub.rects[i];

      switch(r->type) {

      case SUBTITLE_BITMAP:
	vo = calloc(1, sizeof(video_overlay_t));

	vo->vo_start = mb->mb_pts + sub.start_display_time * 1000;
	vo->vo_stop  = mb->mb_pts + sub.end_display_time * 1000;
        vo->vo_canvas_width  = ctx->width;
        vo->vo_canvas_height = ctx->height;

	vo->vo_x = r->x;
	vo->vo_y = r->y;

	vo->vo_pixmap = pixmap_create(r->w, r->h, PIXMAP_BGR32, 0);

	if(vo->vo_pixmap == NULL) {
	  free(vo);
	  break;
	}

	const uint8_t *src = r->pict.data[0];
	const uint32_t *clut = (uint32_t *)r->pict.data[1];
      
	for(y = 0; y < r->h; y++) {
	  uint32_t *dst = (uint32_t *)(vo->vo_pixmap->pm_pixels + 
				       y * vo->vo_pixmap->pm_linesize);
	  for(x = 0; x < r->w; x++)
	    *dst++ = clut[src[x]];

	  src += r->pict.linesize[0];
	}
	video_overlay_enqueue(mp, vo);
	break;

      case SUBTITLE_ASS:
	sub_ass_render(mp, r->ass,
		       ctx->subtitle_header, ctx->subtitle_header_size,
		       mb->mb_font_context);
	break;

      default:
	break;
      }
    }
  }
  avsubtitle_free(&sub);
}