1

I am quite a newby when it comes to defining custom methods/macros in LaTeX. My MWE looks like that:

\documentclass[12pt,a4paper]{article}

\newcounter{myCounter}
\setcounter{myCounter}{1}
\newcommand{\countCounter}[1]{\addtocounter{myCounter}{\advance #1 by 1}\value{myCounter}}
\newcommand{\returnCounter}[1]{\ifnum #1=1 0 \else {\ifnum #1=2 5 \else \relax \fi} \fi}

\begin{document}

    %\returnCounter{\countCounter{0}}
    \addtocounter{myCounter}{1}
    \returnCounter{\value{myCounter}}

\end{document}

What I basically want to do, is to

  • increase my counter myCounter by some number defined in \countCounter
  • use that new counter value for further calculations in \returnCounter

Normally, I would just successively execute these operations (like in the example), however, I want to pass the result as an argument to an external package. For that reason, I tried to pass the result of \countCounter to \returnCounter (commented in the example) but that doesn't work. If, of course, \countCounter would exclusively return a value, then it would work. Therefore my question is: How does one return values while performing operations inside the same command like \countCounter? Thanks!

EDIT: As pointed out in the comments, this approach doesn't work; therefore I will reformulate my problem:

My use case is the inclusion of a .mp4-video into the pdf. I want to have two buttons, forward and backward, which jump to the next/last scene of my video. In an MWE, it looks like this:

\documentclass[12pt,a4paper]{article}
\usepackage{media9}

\begin{document}

    \includemedia[
    label=testvideo,
    activate=pageopen,
    addresource=test.mp4,
    %addresource=test2.mp4,
    flashvars={source=test.mp4},
    ]{}{VPlayer.swf}
    \mediabutton[overface=mouse-over text]{\fbox{\strut backward}}
    %\mediabutton[overface=mouse-over text, mediacommand=testvideo:Play(\returnTime{\countVideo{0}}),
    %   jsaction=testvideo:{
    %       try{app.clearTimeOut(tout)}catch(e){} % kill pending timers
    %       var tout=app.setTimeOut('annotRM.myvideo.callAS("pause")', 2000);}
    %   ]{\fbox{\strut forward}}

\end{document}

The important thing is the commented code: The idea was to have a function passed to Play() that

  1. counts to which scene the jump takes place
  2. returns the correct time stamp.

Additionally, I wanted to have this jsaction-method, to automatically stop the video some seconds after certain jumps.

Has anyone an idea, how this could be achieved?

  • Returning values isn't really possible in LaTeX, you can only let something expand to something. Some operations aren't expandable though (at least not in TeX's mouth), like for example setting a counter. Also your definition of \countCounter seems wrong, there shouldn't be an \advance in the argument of \addtocounter, I think what you want is \newcommand\countCounter[1]{\addtocounter{myCounter}{#1}\value{myCounter}. But this wouldn't return a value, as that is not really possible. So the uncommented lines are the ones which work, and there is no way to make the other line work. – Skillmon Sep 24 at 16:50
  • So, \returnCounter either returns 0 or 5 or \relax. Is this also your eventual use-case? That won't work since \relax isn't something you can perform calculations with. – Werner Sep 24 at 17:07
  • Thanks so far. My use case is the following: I want to implement a forward/backward button with the media9 package which jumps to predefined time stamps. The \returnCounter is supposed to pass the time stamps to the mediabutton as argument; the \countCounter increases or decreases the counter (or leaves it equal if max/min values are reached), which stands for 1-x time stamps in the video. – Ultimate Trick Sep 24 at 17:28
  • @UltimateTrick It would be better if you showed a minimal example with the buttons so that we can work on the counters. \addtocounter{myCounter}{\advance #1 by 1} is wrong though. \addtocounter uses \advance internally, so you should use either \addtocounter{myCounter}{<some amount>} or \advance\c@myCounter by <some amount>. – Phelype Oleinik Sep 24 at 19:36
  • Alright, I will edit my question. – Ultimate Trick Sep 24 at 20:32
1

If I got it right you want two buttons that allow you to fast forward and backward between predefined sections of the video and another button that plays only the current video section and then pauses:

enter image description here

In order to write JavaScript actions for the media buttons we make use of some ActionScript (Flash) methods of VPlayer.swf that are exposed to the JavaScript engine of Acrobat Reader. These methods are documented in Table 6 of the media9 manual.

In order to seek properly within the video, it must be encoded with a sufficient number of key frames. If necessary, use the following command line to re-encode an existing video. It inserts a key frame every second into a video that plays at 30 frames per second:

ffmpeg -i orig-video.mp4 -vf scale="trunc(iw/2)*2:trunc(ih/2)*2"-c:v libx264 -profile:v high -pix_fmt yuv420p-g 30 -r 30 new-video.mp4

Before compiling the present example, download this example-movie.mp4 into the working directory. It is a re-encoded version of the video contained in the mwe package.

\documentclass{article}
\usepackage{media9}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% these are the scene starting times in seconds
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\def\sceneStarts{0,10,30,40,55}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\begin{document}

\noindent%
\includemedia[
  width=0.8\linewidth, height=0.45\linewidth, %16:9
  label=testvideo,
  activate=pageopen,
  passcontext, %right-click menu of VPlayer.swf
  addresource=example-movie.mp4,
  flashvars={source=example-movie.mp4},
]{}{VPlayer.swf}\\[3pt]
\noindent%
\mediabutton[
  jsaction={
    annotRM["testvideo"].callAS("pause");
    try{app.clearInterval(timer);}catch(e){}
    var sceneStarts = [\sceneStarts];
    var tCur=annotRM["testvideo"].callAS("currentTime");
    for(var idx=0; idx < sceneStarts.length; idx++) {
      if(
        idx == sceneStarts.length-1 && tCur > sceneStarts[idx] ||
        tCur > sceneStarts[idx] && tCur <= sceneStarts[idx+1]
      ){
        annotRM["testvideo"].callAS("seek", sceneStarts[idx]); 
        break;
      }
    }
  }
]{\fbox{\strut Prev. Scene}}
\mediabutton[
  jsaction={
    annotRM["testvideo"].callAS("pause");
    try{app.clearInterval(timer);}catch(e){}
    var sceneStarts = [\sceneStarts];
    var tCur=annotRM["testvideo"].callAS("currentTime");
    for(var idx=0; idx < sceneStarts.length-1; idx++) {
      if(tCur >= sceneStarts[idx] && tCur < sceneStarts[idx+1]){
        annotRM["testvideo"].callAS("seek", sceneStarts[idx+1]); 
        break;
      }
    };
  }
]{\fbox{\strut Next Scene}}
\mediabutton[
  jsaction={
    annotRM["testvideo"].callAS("pause");
    var sceneStarts = [\sceneStarts];
    %determine current scene
    var tCur=annotRM["testvideo"].callAS("currentTime");
    var curScene = sceneStarts.length-1;
    for(var idx=0; idx < sceneStarts.length-1; idx++) {
      if(tCur >= sceneStarts[idx] && tCur < sceneStarts[idx+1]){
        var curScene = idx;
        break;
      }
    }
    %checks if we are still inside current scene
    var checkScene = function(){
      var tCur=annotRM["testvideo"].callAS("currentTime");
      if(tCur>=sceneStarts[curScene+1]){
        annotRM["testvideo"].callAS("pause");
        annotRM["testvideo"].callAS("seek", sceneStarts[curScene+1]); 
      }
    };
    try{app.clearInterval(timer);}catch(e){}
    if(tCur<sceneStarts[sceneStarts.length-1]){
      var timer=app.setInterval("checkScene()", 200);
    }  
    annotRM["testvideo"].callAS("play");
  }
]{\fbox{\strut Play Scene}}

\end{document}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.